Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have done quite a bit of digging, and can't seem to find how people handle content restructuring for a variable width element.
For example, if I have a dynamically created horizontal menu it may only have 3 items..
<div>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</div>
And this menu will only have a small width, let's say 400px. I can create a media query to adjust the way it is displayed when the window falls below 400px, however..
If a user adds another item..
<div>
<ul>
<li>Home</li>
<li>About</li>
<li>Location</li>
<li>Contact</li>
</ul>
</div>
Suddenly this menu is larger then 400 px, and so on. My question is, how can I structure my code to handle a variable element width and still control the way that is displayed?
EDIT: When I re-size the browser window on my horizontal menu, at a certain variable width, the inline-block li elements drop below the rest of the menu. Instead of letting each element drop as the screen is compressed I would prefer to make the entire menu drop to a vertical orientation. I cannot simply use a media query, since there are variable amounts of menu items. To illustrate the issue try re-sizing the example code in this fiddle: https://jsfiddle.net/f5Lv73hp/
I don't understand your question, so, consider editing your post with more information, including what do you espect...
By the way:
Horizontal Menu, if you need to keep all list-items with the same width, you can use display-table, there aren't any javascript requirements, just set the list as a table ( see .menu-horizontal css ).
function CasesCtrl($) {
var case1 = $('#case1');
$('button', case1).click(function() {
var list = $('ul', case1);
var len = $('li', list).length;
var newItem = '' +
'<li class="menu-item">' +
'<a class="menu-item-link">Item '+ (len + 1) +'</a>' +
'</li>'
;
list.append(newItem);
});
}
jQuery(document).ready(CasesCtrl);
article {
width: 100%;
padding: 2px;
border: 1px solid black;
margin-bottom: 2em;
overflow: hidden;
}
.menu {
list-style: none;
margin: 0;
padding: 0;
}
.menu-item {
}
.menu-item-link {
background: lightseagreen;
margin: 2px;
padding: 2px 5px;
display: block;
text-transform: uppercase;
line-height: 1;
}
.menu-horizontal {
display: table;
}
.menu-horizontal .menu-item {
display: table-cell;
width: 1%;
white-space: nowrap;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<article id="case1">
<ul class="menu menu-horizontal">
<li class="menu-item">
Item 1
</li>
<li class="menu-item">
Item 2
</li>
<li class="menu-item">
Item 3
</li>
</ul>
<button type="button">Add Menu Item</button>
</article>
Be more specific and I'll edit my answer as you need!
Are you looking for something like this? https://jsfiddle.net/4p18mxg9/2/
I am using javascript to get the width of the ul and applying the width to to media query, that way when you add more li it is not dependent on the content.
var width = document.getElementById('ul').offsetWidth;
document.querySelector('style').textContent +=
"#media screen and (max-width:" + width + "px) { li{float: none; width: 100%; background-color: blue; color: white;}}"
Added some color, to see easier: https://jsfiddle.net/4p18mxg9/3/
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
In my experience, jQuery simplifies DOM navigation immensely as when compared to using pure JavaScript.
Suppose I have two elements #parentA and #parentB and both these two elements have similar children nodes .x .y .z.
Often times, when I use JavaScript without jQuery, if I want to select #parentA's .x I end up accidentally selecting both #parentA .x as well as #parentB.x.
I suppose this is more of a backend developer's therapy session where I am just letting out my frustration with JS rather than asking a question.
The main reason why I am trying to avoid using jQuery is that I am trying to keep the website page weight as low as possible. What would the JavaScript equivalent be of the jQuery code I have below?
HTML
<h2>Colour 1</h2>
<div id="hairColor" class="color-palette">
<ul>
<li style="background: #fc4c4f;"></li>
<li style="background: #4fa3fc;"></li>
<li style="background: #ecd13f;"></li>
</ul>
</div>
<h2>Colour 2</h2>
<div id="skinColor" class="color-palette">
<ul>
<li style="background: #fc4c4f;"></li>
<li style="background: #4fa3fc;"></li>
<li style="background: #ecd13f;"></li>
</ul>
</div>
SCSS
.color-palette {
background: #384047;
min-height: 60px;
margin: 0 auto;
width: 100%;
border-radius: 5px;
overflow: hidden;
ul {
list-style: none;
margin: 0;
float: left;
padding: 10px 0 20px;
width: 100%;
text-align: center;
li {
display: block;
height: 54px;
width: 54px;
border-radius: 60px;
cursor: pointer;
border: 0;
box-shadow: 0 3px 0 0 #222;
display: inline-block;
margin: 0 5px 10px;
}
.selected {
border: 7px solid #fff;
width: 40px;
height: 40px;
}
}
}
JS
$(".color-palette").on("click", "li", function(){
$(this).siblings().removeClass("selected");
$(this).addClass("selected");
color = $(this).css("background-color");
});
// What would the equivalent code be using vanila JavaScript?
// var colors = document.querySelectorAll("#hairColor ul li");
To make that without something like jQuery, you'll need a few iterators (a for loop or something), is 100% doable and is not that hard but beware, is a larger piece of code.
What that code is doing is assigning the click event to the color-palette container and filtering by the target element to match the LI, if you want you can simplify it by just assigning the click to the li directly and check on the parent.
This is a starting point to replicate the same behavior:
document.querySelectorAll('.color-palette').forEach((palette) => {
palette.addEventListener('click', (e) => {
e.target.parentNode.querySelectorAll('li').forEach((li) => {
li.classList.remove('selected');
})
if (e.target.tagName.toLowerCase() !== 'li') {
return;
}
e.target.classList.add('selected');
})
})
This could be simplified a bit but is a draft and should be working.
Something like this should do the trick:
let triggers = document.querySelectorAll('li')
triggers.forEach(el => {
el.addEventListener('click', () => {
[...triggers].map(x => x.classList.remove('selected'))
el.classList.add('selected');
let color = el.style.backgroundColor;
})
})
First, you add eventlisteners to each li element, and when clicking on one, you create an array of the elements by using the spread ... operator. Chain this array afterwards with the map operator to remove the selected class. And finally, you simply add the selected class to the element you've clicked.
I'm not exactly sure how to better phrase the title above so if you can think of a more clear and concise title feel free to re-phrase it.
I am creating a generic tool-tip with HTML, CSS, and Javascript (no jQuery, Angular, etc.). I've made it to a point where everything looks pretty clean, until I resize the window and scroll down. Now, from my understanding, mobile devices do not have an onmouseover or onmouseout event and therefore I do not need to account for this; however, if I take into account the smaller screens of some laptops (I've seen 10 inch screens) then this could be an issue.
When I hover over one of the elements (they are all a elements in this example), the tool-tip appears as it should, however when I resize as I described above, the onmouseout event is firing because the mouse is technically over the tool-tip, not the element anymore. I thought that offsetting from the position of the element by its height plus five pixels that I would be safe from that issue, but it seems that the position isn't the position I'm expecting.
I am currently using getBoundingClientRect() to calculate the positions but I believe this is based on the view port position while I think I'm needing based on the position in the page instead that way as the page moves so does where the tool tip is. I've included my code below and you can test it out and see what I'm talking about.
var tooltip = document.getElementById("globalTooltip");
function showTooltip(sender) {
var senderBounds = sender.getBoundingClientRect();
var top = senderBounds.y + senderBounds.height + 5;
tooltip.dataset.owner = sender;
tooltip.innerHTML = sender.dataset.tooltip;
tooltip.classList.add(sender.dataset.tooltiptype);
if (top + tooltip.getBoundingClientRect().height + 5 > window.innerHeight)
top = senderBounds.y - tooltip.getBoundingClientRect().height - 5;
tooltip.style.top = top + "px";
tooltip.style.left = (senderBounds.x + 5) + "px";
tooltip.classList.add("active-tooltip");
}
function hideTooltip(sender) {
tooltip.style.left = "-250px";
tooltip.classList.remove("error");
tooltip.classList.remove("warning");
tooltip.classList.remove("success");
tooltip.classList.remove("neutral");
tooltip.classList.remove("active-tooltip");
}
body {
margin: 0;
text-align: center;
}
.disabled-link {
color: #777;
cursor: default;
}
li {
padding: 5px;
list-style-type: none;
}
.tooltip {
position: absolute;
padding: 10px;
cursor: default;
border-radius: 25px;
color: #333;
opacity: 0;
transition: all 0.2s ease-in-out;
max-width: 30vw;
}
.neutral { background-color: #ddd; }
.success { background-color: #7c7; }
.warning { background-color: #fc3; }
.error { background-color: #f55; }
.active-tooltip { opacity: 1; }
<div class="container">
<ul>
<li>
<a class="disabled-link"
data-tooltip="This link is available in another location."
data-tooltiptype="warning"
onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)">
Hover Over This Disabled Link</a>
</li>
<li>Some Active Link</li>
<li>
<a class="disabled-link"
data-tooltip="Something great is coming soon!"
data-tooltiptype="success"
onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)">
Hover for more details...</a>
</li>
<li>Some Active Link</li>
<li>
<a class="disabled-link"
data-tooltip="This area is currently under maintenance."
data-tooltiptype="error"
onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)">
Another Disabled Link</a>
</li>
<li>Some Active Link</li>
<li>Some Active Link</li>
<li>Some Active Link</li>
<li>
<a class="disabled-link"
data-tooltip="This is an example of what happens when the text supplied to the tooltip is rather verbose instead of the enjoyable concise messages that are typically used to relay information instead. No one likes to read a novel in a tooltip, but hey, it's not my decision, it just has to be accounted for due to an excessive and old page."
data-tooltiptype="neutral"
onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)">
Really Verbose Message</a>
</li>
</ul>
</div>
<i id="globalTooltip" data-owner="none" class="tooltip"></i>
How can I ensure the tool-tip is always offset from the element instead of flying in over it?
First, I should mention that I'm about 4-weeks new to the coding world, and this is the first time I'm trying to make (what I thought would be) a simple site.
I have seen many similar questions on Stack Overflow, but in trying to adapt the code samples provided in the solutions, the solution would stop working.
So, the current hurdle is:
I have a menu defined in HTML with a sub-menu in one of the <li> elements ("Portfolio"), and that <li> element contains the character ▼ (▼).
I set up an onclick event for that <li> element so that when it was clicked it would do two things: expand/display the sub-menu <li> elements directly below it (pushing the other <li> elements in the menu further down), and replace the ▼ character with a ▲ character (▲)... until the <li> element was clicked again to shrink/hide the sub-menu.
I'm not sure if it matters, but this menu is inside a grid item because the page is set up using CSS Grid.
So basically:
HOME
ABOUT US
PORTFOLIO ▼
INFORMATION
CONTACT
...would become:
HOME
ABOUT US
PORTFOLIO ▲
LINK 1
LINK 2
LINK 3
INFORMATION
CONTACT
No matter how I set up my classes and IDs, I cannot get the arrow symbol to swap, and somewhere along the line, I messed up the coding and now the sub-menu doesn't even expand anymore.
It's likely embarrassingly bad code (given that I've tried to mash together bits from samples I've seen) but here is what I have. Thanks in advance.
var arrowstring = document.getElementById("arrowdirection").innerHTML;
document.getElementById("IDforPortfolioLink").classList.toggle("show");
if (IDforPortfolioLink.classList.contains('show')) {
arrowstring = "▲"
} else {
arrowstring = "▼"
}
arrowdirection.textContent = arrowstring;
}
.sub-menu-content {
display: none;
position: absolute;
}
.sub-menu-content a {
display: block;
}
.sub-menu-content a:hover {
background-color: green;
}
.show {
display: block;
}
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<ul class="menu">
<li>Home</li>
<li>About us</li>
<li class="LinkForPortfolio" id="IDforPortfolioLink" onclick= "myFunction()">LINK <span class="arrow" id= "arrowdirection">▼</span><div class="sub-menu-content" id="myportfolio">
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
</li>
<li>Information</li>
<li>Contact</li>
</ul>
</body>
</html>
Well, your code had so many flaws I had to rewrite it.
I'll explain everything that I possibly can of what I did here:
I changed the HTML a bit: I have added div's, instead of ul's with li's, inside a nav(container). It's more indicated to do so because it keeps the markup clean, and is less harder to debug.
I have assigned nav a display: flex; justify-content: center; align-items: center; which centers the divs inside nav, and inlines them. I did so with nav div, which pretty much centered the text inside of them.
I have removed all of the classes expect of .portfolio because it's useless to have that many classes.
I made div.expand-portfolio a child of div.portfolio, which in itself(.expand-portfolio) has another ul child, which holds the links. You might've noticed that I've added .portfolio a position: relative; and .expand-portfolio a position: absolute;. I did that because, I wanted to take .expand-portfolio out of the document flow, which basically means I wanted to make .expand-portfolio not interact with any element on the page. Now, when assigning position: absolute; to a child inside a container, the child's position is going to be relative to the document and not the parent. This is why you may add position: relative; to the parent.
I created a separate class called .expanded which gives .expand-portfolio a height of 150px when assigned to it.
You also might have noticed I gave the divs inside the nav a transition: 500ms ease, what that does is make the transition between the properties smooth, and not sudden. You may remove that property from them if you don't want that.
Now, the javascript.
When I made those 3 variables, which are the references of the elements from the page, you noticed I used document.getElementsByClassName followed by a [0]. What document.getElementsByClassName() returns is: a nodelist. Documentation here. It's basically a sort of "array", and with [0] appended to it, I select only the first and only element of the page with that class.
You may have observed I added the onclick function in the javascript file. Personal preference. I said that when I click the portfolio button, first, you should change that span's innerHTML. (the span element holds the actual symbol). I also said you should toggle the .expanded class. And, I made an if statement, checking if .expand-portfolio doesn't contain the class. If it doesn't, you can pretty much see what it does.
I hope it helps. If you have any more questions, ask them in the comments.
var portfolio = document.getElementsByClassName("portfolio")[0];
var portfolioInner = document.getElementsByClassName("inner-html")[0];
var expandPortfolio = document.getElementsByClassName("expand-portfolio")[0];
portfolio.onclick = function(){
portfolioInner.innerHTML = "▲";
expandPortfolio.classList.toggle("expanded");
if(!expandPortfolio.classList.contains("expanded")){
portfolioInner.innerHTML = "▼"
}
};
html, body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
.menus-container {
height: 100%;
width: auto;
}
.menus-container > div {
padding: 10px 10px 5px;
transition: 500ms ease;
width: 30%;
height: 100%;
cursor: pointer;
}
.expand-portfolio {
overflow: hidden;
width: 100px;
height: 0;
background-color: #000;
transition: 500ms ease;
}
.expand-portfolio ul {
padding-left: 25px;
}
.expand-portfolio ul li {
padding: 10px 0 10px 0;
color: #fff;
}
.portfolio span {
margin-left: 5px;
}
.expanded {
height: 150px;
}
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="menus-container">
<div>Home</div>
<div>About Us</div>
<div class="portfolio">Portfolio <span class="inner-html">▼</span>
<div class="expand-portfolio">
<ul>
<li>LINK 1</li>
<li>LINK 2</li>
<li>LINK 3</li>
</ul>
</div>
</div>
<div>Information</div>
<div>Contact</div>
</div>
</body>
</html>
I have a horizontally sliding line of elements within a fixed width, so you have to scroll left an right to see all the elements. See JS Fiddle and text-only example below.
Hi | Hello | How do you do | Fine thanks | Good weather this time of year
My question is: How can I center any given element horizonally? Eg. Put the horizontal center of element number 3 in the horizontal center of the surrounding div.
If the element can't be centered because it is at the beginning of the line for example, that's OK, then the H-position should simply be 0. It should only be centered as much as it can be.
So something like this? You can use a combination of the following native properties scrollLeft, offsetLeft, and offsetWidth.
var items = document.querySelectorAll('.wrapper ul li');
function centerItems(which) {
var wrapper = items[which].offsetParent;
wrapper.scrollLeft =
(items[which].offsetLeft + items[which].offsetWidth / 2)
- wrapper.offsetWidth / 2;
}
html {
background: #eee;
}
body {
width: 320px;
background: white;
font-family: sans-serif;
}
.wrapper {
overflow-x: scroll;
position: relative;
}
ul {
white-space: nowrap;
}
li {
display: inline-block;
color: #898;
background: #efe;
padding: 8px;
}
<p>Hello!</p>
<button onclick="centerItems(0)">1</button>
<button onclick="centerItems(1)">2</button>
<button onclick="centerItems(2)">3</button>
<button onclick="centerItems(3)">4</button>
<button onclick="centerItems(4)">5</button>
<div class="wrapper">
<ul>
<li>Short</li>
<li>Very long line here</li>
<li>Medium line</li>
<li>Another one Another one Another one</li>
<li>Yet another</li>
</ul>
</div>
<p>Goodbye!</p>
I have an idea for my personal website layout. I'd like stacked menu items on the left side (with like 10% width) and content on the right side. By 'vertical abacus' (the original calculator with beads on a rod), I'd like menu items to appear as boxes of varying colors with a set height for each box. Because they're a set height, there will be a large portion of empty space (colored depending on what menu you select).
Utilizing the new HTML5/CSS3, I'd like to know how I'd go about creating the menu so that when you select an item, that particular item (and the items above it) slide up and stack to the top, while changing the color of the empty space below it according to the color of the respective menu item. When a menu item that is stacked at the top is selected, the items stacked below it will move back down to their original position.
First visit to the website:
After clicking 'Page2':
(I'm such an excellent MSPaint artist, I know.)
Did I lose anyone yet? :)
Would I have to tweak this process with Javascript?
I'm not asking someone to code it for me (though obviously welcome), I just have no idea where to start since W3Schools.com is frowned upon and I have an amateur knowledge of the new features in HTML5/CSS3. Would something as seemingly simple as this be difficult to begin with?
Any help is greatly appreciated! :)
Create a Fiddle for you:
http://jsfiddle.net/M8bQH/
Please adapt Width/Height and colors to your needs!
HTML:
<div id="container">
<div id="sideBar">
<ul id="myMenu">
<li class="topic1 activeItem">Home</li>
<li class="topic2">Page 2</li>
<li class="topic3">Page 3</li>
</ul>
</div>
<div class="mainContent activeContent">
Content1
</div>
<div class="mainContent">
Content2
</div>
<div class="mainContent">
Content3
</div>
</div>
JavaScript (jQuery needed!)
$('#myMenu li').click(function(){
// Set active menu item
$('#myMenu li').removeClass('activeItem');
$(this).addClass('activeItem');
// Set active content according to item
$('.mainContent').removeClass('activeContent');
$('.mainContent').eq($(this).index()).addClass('activeContent');
// Adapt background color of content according to item
$('.mainContent.activeContent').css('background-color', $(this).css('background-color'));
});
CSS:
#container {
width: 800px;
height: 600px;
}
#myMenu {
list-style-type:none;
padding: 0;
margin: 0;
}
#myMenu li {
width: 100px;
height:48px;
border-bottom: 5px solid black;
-webkit-transition: height linear 0.5s; /* For Safari 3.1 to 6.0 */
transition: height linear 0.5s;
}
#myMenu li:last-child {
border-bottom: 0px;
}
#sideBar {
width: 100px;
height: 600px;
float:left;
border-right: 5px solid black;
}
.mainContent {
width: 700px;
height: 100%;
background-color: gray;
display: none;
}
.topic1 {
background-color: gray;
}
.topic2 {
background-color: #33CCFF;
}
.topic3 {
background-color: #99FF00;
}
.activeItem {
height: 494px !important;
}
.activeContent {
display: block !important;
}