css :hover effect on current and previous elements - javascript

I have many unordered lists of 5 li in each like
<ul class="Rank">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
I want to change background-color of current li:hover element and all previous li elements in that list. Suppose, if I hover over 3rd li then 3rd, 2nd and 1st li should have background-color:#00f;
I can do it in jQuery or JavaScript, but I want it in pure CSS. Currently following this article: http://css-tricks.com/useful-nth-child-recipies/
I can change background of currently hovered li element with this .Rank li:hover but cannot understand how can I change background-color of the previous elements of that current .Rank list.
From above article I also learnt to change background until nth-chid but cannot figure out how to apply :hover on it.
.Rank li:nth-child(-n+5)
{
background-color:#00f;
}

http://jsfiddle.net/coma/PLBYG/2/
or
http://jsfiddle.net/coma/PLBYG/3/
ul.rank {
margin: 0;
padding: 0;
list-style: none;
}
ul.rank > li {
position: relative;
margin: 0;
height: 30px;
background: #ccc;
transition: background-color 350ms;
}
ul.rank:hover > li {
background-color: #00f;
}
ul.rank > li + li {
margin-top: 10px;
}
ul.rank > li:hover ~ li {
background: #ccc;
}
ul.rank > li + li:before {
content: "";
display: block;
position: absolute;
top: -10px;
left: 0;
right: 0;
height: 10px;
}
or!!!
http://jsfiddle.net/coma/PLBYG/4/
ul.rank {
margin: 0;
padding: 0;
list-style: none;
transform:rotate(180deg);
-ms-transform:rotate(180deg);
-webkit-transform:rotate(180deg);
}

Posting my answer for reference (to those who come viewing this later like I did).
Here is a solution that doesn't use :before or :after.
http://jsfiddle.net/nLCZK/
It uses float: right for all the lis, and you also have to put the lis in opposite order you want them to appear.

Related

One-liner auto wrapping list with inline separators, but: don't display separator marker at line ending and line starting? [duplicate]

This question expands upon 'Separators For Navigation' by asking, how it is possible to remove the separators at the line breaks cause by viewport size.
Wide Viewport
-> Item 1 | Item 2 | Item 3 | Item 4 | Item 5 <-
Small Viewport
-> Item 1 | Item 2 | Item 3 <-
-> Item 4 | Item 5 <-
Here is a fiddle that shows how a pipe remains at the line break:
Fiddle.
I'm interested in a css-only solution, but javascript is acceptable if it provides the only possible solution.
Explanation
You can exploit fact that trailing and line trailing white space automatically collapses:
document.write(
'word<b style="background: red; outline: 1px solid blue;"> </b>'
.repeat(42)
);
As you can see there are red spaces with blue outlines between words, but the very last and and two at line ends lack the red area because it's width collapsed to zero: that is the white-space collapsing in effect.
It is possible to adjust width with word-spacing and use pseudo element instead, so setting inline ::after { content: ' '; word-spacing: 2em; } gives you wide inline rectangle that can have decorated backgrounds or borders but disappears when it is not between words.
Simplified example
Simplified use case (from https://codepen.io/myf/pen/dyOzpZM, tested just in 2021-02 evergreen Firefox and Chromium, will not work in pre-Chromium Edge; for more robust example see the second snippet below):
ul {
text-align: center;
padding: 0;
}
li {
display: inline;
}
li::after {
/*
This has to be space, tab or other
breakable white-space character:
*/
content: " ";
word-spacing: 1em;
background-image: linear-gradient(
-0.2turn,
transparent 0 calc(50% - 0.03em),
currentcolor 0 calc(50% + 0.03em),
transparent 0
);
}
/*
That's it: just inline text
with styled ::after spaces
that collapse at line breaks
and at the end of the element.
That's basically how spaces work in text.
*/
/*
Unrelated whimsical effects:
*/
body { background: #456; color: #fed; min-height: 100vh; margin: 0; display: flex; align-items: center; }
ul { --dur: 3s; font-family: Georgia, serif; font-size: min(7vw, calc(100vh / 7)); margin: 0 auto; position: relative; padding: 0 1em; -webkit-text-fill-color: #999; text-transform: capitalize; animation: poing var(--dur) infinite alternate ease-in-out; }
#keyframes poing { from { max-width: 3.4em; } to { max-width: min(19em, calc(100vw - 2em)); color: lime; } }
ul::before, ul::after { -webkit-text-fill-color: currentcolor; position: absolute; top: 50%; transform: translatey(-50%); animation: calc(var(--dur) * 2) calc(var(--dur) * -1.5) infinite forwards linear; }
ul::before { content: "☜"; left: 0; animation-name: a !important; }
ul::after { content: "☞"; right: 0; animation-name: b !important; }
#keyframes a { 50% { content: "☛"; } }
#keyframes b { 50% { content: "☚"; } }
ul:hover, ul:hover::before, ul:hover::after { animation-play-state: paused; }
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
<li>gazonk</li>
<li>qux</li>
<li>quux</li>
</ul>
It uses flat list with single word items, so is not very relevant for real-world usage.
More realistic example with elements highlights
nav {
text-align: center;
padding-right: 1em; /* = li::after#word-spacing */
}
ul {
display: inline;
margin: 0;
padding: 0;
}
li {
display: inline;
/*
white-space: nowrap should be moved to child A
because IE fails to wrap resulting list completely
*/
}
li::before {
content: ' ';
/*
this content is important only for Chrome in case
the HTML will be minified with *no whitespaces* between </li><li>
*/
}
li::after {
content: ' ';
/*
this is actual placeholder for background-image
and it really must be space (or tab)
*/
white-space: normal;
word-spacing: 1em;
/*
= nav#padding-right - this actually makes width
*/
background-image: radial-gradient(circle, black, black 7%, transparent 15%, transparent 35%, black 45%, black 48%, transparent 55%);
background-size: 1em 1em;
background-repeat: no-repeat;
background-position: center center;
opacity: 0.5;
}
/*
no need to unset content of li:last-child::after
because last (trailing) space collapses anyway
*/
a {
white-space: nowrap;
display: inline-block; /* for padding */
padding: 1em;
text-decoration: none;
color: black;
transition-property: background-color;
transition-duration: 500ms;
}
a:hover {
background-color: #ccc;
}
/*
For demonstrative purposes only
Give items some content and uneven width
*/
nav:hover > ul > li {
outline: 3px dotted rgba(0,0,255,.5);
outline-offset: -3px;
}
nav:hover > ul > li::after {
opacity: 1;
background-color: rgba(255, 0, 0, .5);
}
nav:hover > ul > li:hover {
outline-style: solid;
}
nav:hover > ul > li:hover::after {
background-color: cyan;
}
nav:hover > ul > li > a {
outline: 3px solid rgba(0,255,0,.5);
outline-offset: -3px;
}
nav > ul {
counter-reset: c;
}
nav > ul > li {
counter-increment: c;
}
nav > ul > li > a::before {
content: counter(c, upper-roman) '. ';
letter-spacing: .3em;
}
nav > ul > li > a::after {
content: ' item ' counter(c, lower-roman);
word-spacing: .3em;
letter-spacing: .1em;
transform: translatex(.1em);
display: inline-block;
}
<nav>
<ul><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
</ul>
</nav>
<!-- For demonstrative purposes is content of links made by CSS
-->
(Originally from https://jsfiddle.net/vnudrsh6/7/) This proof-of-concept uses background-image of "eventually colapsing" CSS generated content space after each <li>. Tested in 2016 in Firefox, Chrome and IE11.
Obviously you might need to use some character or more complex shape as divider. Naturally you can use (vector) background-image, and you can even use text in SVG, although making it correspond with surrounding ("real") text might be quite daunting.
Bare-bones with SVG
Minimal working example without any "list" element, with textual ❦ fleuron:
body {
text-align: center;
}
b::after {
content: " ";
word-spacing: 16px;
background: url("data:image/svg+xml;charset=utf-8,\
<svg xmlns='http://www.w3.org/2000/svg' \
viewBox='-3,-15,16,16'>\
<text>❦</text>\
</svg>");
}
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
Other notable answers:
Same technique used in overlooked Liphtier's answer from 2014. (I've found that one long after posting this answer, so to my disappointment I cannot claim my answer is was first.)
Same technique used in few months younger Tom Robinson's answer.
gfullam's answer using flex-box, very impressive alternative with plain over-extending borders and different spacing due flex arrangement.
Oriol's answer for left-aligned list using overflow hidden and real character in pseudo.
A different solution from that same CSS: Last element on line seems like it would work here.
HTML:
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
CSS:
div {overflow: hidden; margin: 1em; }
div ul { list-style: none; padding: 0; margin-left: -4px; }
div ul li { display: inline; white-space: nowrap; }
div ul li:before { content: " | "; }
(Fiddle)
If you have static width of your element you can calculate by the media-screen.
If not use script
body {
text-align: center;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
&:not(:last-child):after {
content: ' |';
}
}
#media screen and (max-width: 265px) {
li {
display: inline-block;
&:not(:last-child):after {
content: '';
}
}
}
Nice question. For the life of me, I can't think of a water-tight CSS-only solution I'm afraid...
I've modified an old solution to a similar question posted a while back: CSS: Last element on line. Funnily enough I was looking for a solution to another problem I had a while back and stumbled across this - been bookmarked since!
Here's a fiddle with my updates: https://jsfiddle.net/u2zyt3vw/1/
HTML:
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
CSS:
body {
text-align: center;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
&:not(:last-child):after {
content: ' |'
}
}
li.remove:after {
content: none;
}
jQuery:
$(window).on("resize", function () {
var lastElement = false;
$("ul > li").each(function() {
if (lastElement && lastElement.offset().top != $(this).offset().top) {
lastElement.addClass("remove");
}
lastElement = $(this);
}).last().addClass("remove");
}).resize();
NOTE - it works best onload at the moment, resizing causes a few issue even if I use toggleClass(). So keep pressing "Run" every time you resize the view. I'll work on it and get back to you..
My implementation with JavaScript: https://jsfiddle.net/u2zyt3vw/5/
Hit "Run" again after you've resized the window.
You can also add event listeners such as onresize. Here's the JS:
var listItems = document.getElementsByTagName("li");
var listItemsWidth = [];
var listItemsDistance = [];
for (let i = 0; i < listItems.length; i++) {
listItemsWidth[i] = listItems[i].offsetWidth;
listItemsDistance[i] = listItems[i].getBoundingClientRect().right;
}
for (let i = 0; i < listItems.length; i++) {
if (listItemsDistance[i] == Math.max.apply(null, listItemsDistance)) {
listItems[i].classList -= "notLast";
} else {
listItems[i].classList = "notLast";
}
}
I added the notLast class to all of your elements, and that's what contains the :after pseudo-element with the pipe. This script removes this class from the ones that are closer to the right edge of the container.
I also messed around with the :after pseudo-element and made it position:absolute; for dark reasons.

How to get mega menu with nested UL without JS?

We have the following html structure for our menu (see codepin). We would like to modify the menu without having to use JS on page load to move any elements around.
Here is what I tried, but cannot get the custom-dropdown to show like the screenshot below.
Here is my codepin that I have so far, but we are having hard time getting it to align in two columns like the screenshot. The goals below have been simplified, but should be applicable to other links like Category and Company as well since they follow similar structure.
Goal (see screenshot):
On hover of Testing 1, Collaboratively testing 1 and transition accurate should display
On hover of Collaboratively testing 1 then the Enthusiastically communicate cross-platform and Uniquely reconceptualize accurate should display
Screenshot:
Underline below Testing 1 is to simulate on hover effect
Grey background behind Collaboratively Testing is to indicate on hover effect, which results in goal #2 where they are display to the right.
Multi-Level Drop Down Menu with Pure CSS
ul {
list-style: none;
padding: 0;
margin: 0;
background: #1bc2a2;
}
ul li {
display: block;
position: relative;
float: left;
background: #1bc2a2;
}
/* This hides the dropdowns */
li ul { display: none; }
ul li a {
display: block;
padding: 1em;
text-decoration: none;
white-space: nowrap;
color: #fff;
border-bottom: 3px solid #1bc2a2
}
ul li a:hover {border-bottom: 3px solid #2c3e50}
/* Display the dropdown */
li:hover > ul {
display: block;
position: absolute;
}
li:hover li { float: none; }
li:hover a { background: #1bc2a2; }
li:hover li a:hover { background: #2c3e50; }
.main-navigation li ul li { border-top: 0; }
/* Displays second level dropdowns to the right of the first level dropdown */
ul ul ul {
left: 100%;
top: 0;
}
/* Simple clearfix */
ul:before,
ul:after {
content: " "; /* 1 */
display: table; /* 2 */
}
ul:after { clear: both; }
here comes your html code
<h1>Multi-Level Drop Down Menu with Pure CSS</h1>
<ul class="main-navigation">
<li>Home</li>
<li>Front End Design
<ul>
<li>HTML</li>
<li>CSS
<ul>
<li>Resets</li>
<li>Grids</li>
<li>Frameworks</li>
</ul>
</li>
<li>JavaScript
<ul>
<li>Ajax</li>
<li>jQuery</li>
</ul>
</li>
</ul>
</li>
</ul>

load html into div, menu, switch

I need to finish javascript for load html page into div. I want load page1,page2 and so on into div id="content". If someone help me I will grateful. Thanks
Here is jsfiddle of this code
HTML
<div id="menu">
<nav>
<ul>
<li ><a class="active" href="1.html" ><b>Page1</b></a></li>
<li ><a href="2.html" ><b>Page2</b></a>
</li>
<li ><b>Page3</b>
</li>
<li ><b>Page4</b></li>
<li ><b>Page5</b></li>
</ul>
</nav>
</div>
<div id="content"> </div>
CSS
nav ul ul {
display: none;
}
nav ul li:hover > ul {
display: block;
}
nav ul {
background: rgb(1, 1, 1);
box-shadow: 0px 0px 9px rgba(0, 0, 0, 0.15);
padding: 0 20px;
border-radius: 0px;
list-style: none;
position: relative;
display: inline-table;
font-family: Times New Roman;
font-size: 70%;
}
nav ul:after {
content:"";
clear: both;
display: block;
}
nav ul li {
float: left;
}
nav ul li {
float: left;
font-family: Arial;
font-size: 1;
}
nav ul li a:hover, nav ul li a.active, nav ul li a.visited {
background: rgb(177, 2, 10);
}
nav ul li:hover a {
color: rgb(255, 255, 255);
}
nav ul li a {
display: block;
padding: 5px 45px;
color: rgb(255, 255, 255);
text-decoration: none;
position: relative;
}
#menu {
position: relative;
width: 780px;
height: 35px;
left: 50%;
margin-left: -388px;
overflow: hidden;
top: -20px;
}
#content {
position: relative;
float: center;
width: 770px;
height: 670px;
clear:both;
margin: 0 auto;
border-radius: 7px;
overflow: hidden ;
top: 0px;
border: 3px solid black;
}
JAVASCRIPT
$(document).ready(function(){
$('nav ul li a').click(function(){
$('nav ul li a').removeClass('active');
$(this).addClass('active');
});
});
Assuming your href reference the file with the contents that you want to show, you can use .load(). You can get the href property using .prop().
Prevent the default action (redirecting to a new page) when your anchors are clicked.
You may also want to trigger the this functionality on page load for the .active nav button. I've added a filter and a click trigger afterwards for this reason.
$(document).ready(function () {
var $navAnchors = $('nav ul li a');
$navAnchors.click(function (e) {
var $this = $(this);
e.preventDefault();
$navAnchors.removeClass('active');
$this.addClass('active');
$('#content').load($this.prop('href'));
}).filter('.active').click();
});
Notice I've assigned your matching jQuery collection to a variable, to save you making repeat selections. This way nav ul li a is only searched for once, on DOM load.
Use $.get.
$(document).ready(function(){
$('nav ul li a').click(function(e){ // when a nav link ('a' tag) is clicked...
$('nav ul li a').removeClass('active'); // remove the css class "active" from any nav links.
$(this).addClass('active'); // add the css class "active" to the one we clicked
e.preventDefault(); // <-- important! // prevent the page from navigating away
var page = this.href; // get the url the link would normally go to
$.get( page, function( data ) { // in the background, get the content of the page for the link we have clicked
$( "#content" ).html( data ); // load the content we have into the element with id "content"
});
});
});
If you're saying that the page is empty when you first load it, that's expected. If you want it to load something, you'll need to manually fire off the click event when the page loads.. something like:
$('nav ul li a.active').click(); // Get the nav link which has class "active", and fire the click() event.
... should do the trick.
Note -- fiddle won't work, as it doesn't support AJAX stuff very well.
Second Note - George's answer is a simpler version of this. Use that. :)

How to resize the horizontal menu with respect to its li?

I have 7 menus in my code.Sometimes it may be 6 based on the usertype.If admin is entered it will be 7.User may have only 6 menus.
How can resize the menu dynamically.
For that I used the code
<div id="menu">
<ul>
<li>home1</li>
<li>home2</li>
<li>home3</li>
<li>home4</li>
<li>home5</li>
<li>home6</li>
<li>home7</li>
</ul>
</div>
How can I do this with jquery?
EDIT
$(document).ready(function() {
if ( $('#menu ul li').length > 6 ) {
$('#menu ul li').css('width','14.5%');
}
else
{
$('#menu ul li').css('width','16.6%');
}
});
}
});
Assuming that the desired outcome is for the above menu to be rendered in one line, regardless of the exact number of items -
the best way to do this would be with tables, as they have native behavior for this type of thing ( taking up a long line and distributing items evenly over it ). The good thing is that we can easily fake that behavior using
#menu { display: table; width: 100%; }
#menu ul { display: table-row; }
#menu ul li { display: table-cell; }
this will automatically distribute your <li>s over a long line, using the containers width.
You can also see a jsFiddle with an example of the above.
Assuming hexblot's answer isn't what you wanted and you want to distribute LI's of a varying width across the width of a container element, without the LI's necessarily taking up the full-width of your navigation bar then use this:
http://jsfiddle.net/sxGMZ/
#menu ul {
display: block;
text-align: center;
width: 100%;
background: brown;
}
#menu ul li {
display: inline-block;
height: 30px;
padding: 10px 12px 0 12px;
background: #ccc;
}
Instead of table cells use display inline-block:
#menu { display: inline-block;background:#000; }
#menu ul { display: inline-block; margin:0;padding: 0; }
#menu ul li { display: inline-block; margin:0; padding: 0;}
#menu ul li a { display: inline-block; padding: 10px; color: #fff;}
#menu ul li a:hover { color: #ff0;}
Fiddle here: http://jsfiddle.net/BtvY9/

Maintaining a css :hover effect for all items up a nested list chain

So, I have DOM that looks like this:
<ul id="nav">
<li><a>Hello</a></li>
<li>
<a>OuterMenu</a>
<ul>
<li><a>InnerMenu1</a>
<ul><li><a>InnerMenu2</a></li><li><a>Item 1</a></li><li><a>Item 2</a></li></ul>
</li>
</ul>
</li>
</ul>
which looks like this:
+Hello +OuterMenu
----InnerMenu1--------------InnerMenu2
----Other list item Item 1
Item 2
That is, the first menu is horizontal, the next menu is directly below the first menu, and all subsequent inner menus appear directly to the right [see example here].
This works fine, but I need the hover styles for each outer menu to persist as each inner menu is selected. When the user is hovering over Item 1, Item 1, InnerMenu, and OuterMenu should be highlighted, and when the user moves off of the whole menu tree, then and only then should OuterMenu no longer be highlighted. Is there a better way to do this than trying to manage a hover and mouseout event on every single list item?
I'm looking for a clean implementation here.
Check out Stu Nicholls great css-only work on just this issue.
I don´t know what you have already, but if you use something like:
#nav > li:hover > a {
// outer menu highlight
}
it should highlight the outer menu also when you are on a sub-menu item.
The same technique can be applied to all levels, but it depends on your browser compatibility requirements as li:hover will not work in older IE versions.
For completeness
/* second level */
#nav > li > ul > li:hover > a {
}
/* third level */
#nav > li > ul > li > ul > li:hover > a {
}
Simply using the :hover psuedo-class on your li will apply even when you are over a descendant element. Here's a working example showing that this is true: http://jsfiddle.net/eMyHE/; hover over InnerMenu2 and you'll see InnerMenu1 and OuterMenu highlight.
Also, you might be interested in my 8-years-old CSS-only hierarchical menu tests, part of some ancient code that uses JavaScript for hierarchical menus.
This isn't my work, I'm just passing it on. It looks like it's the same answer as JakeParis's, but in JSFiddle form. http://jsfiddle.net/XPE3w/7/ This is for HTML with a ul>li>a structure (see the link if this doesn't make sense).
ul {
font-family: Arial, Verdana;
font-size: 14px;
margin: 0;
padding: 0;
list-style: none;
}
ul li {
display: block;
position: relative;
float: left;
}
li ul {
display: none;
}
ul li a {
display: block;
text-decoration: none;
color: #ffffff;
border-top: 1px solid #ffffff;
padding: 5px 15px 5px 15px;
background: #2C5463;
margin-left: 1px;
white-space: nowrap;
}
ul li a:hover {
background: #617F8A;
}
li:hover ul {
display: block;
position: absolute;
}
li:hover li {
float: none;
font-size: 11px;
}
li:hover a {
background: #617F8A;
}
li:hover li a:hover {
background: #95A9B1;
}

Categories

Resources