I have a perfectly working html/css sprite nav. When each link in its unordered list is hovered over, the background sprite image changes as expected, for that specific item. I want to make the entire nav sprite move position based on which linked is hovered over, so that the effect for any one link changes the background for the entire unordered list.
Reason: the edges of each inline are not vertical, they are at a 45 degree angle, so changing a traditional block background doesn't work so well. Changing the entire background will accomodate and work perfectly.
Code in use currently:
CSS:
#nav {
position: relative;
float: right;
background: url('../gfx/nav.gif');
width: 498px;
height: 23px;
margin: 110px 2px 0 0;
border: 0;
padding: 0;
}
#nav li {
position: absolute;
top: 0;
margin: 0;
border: 0;
padding: 0;
list-style: none;
}
#nav li, #nav a {
height: 23px;
display: block;
}
#nav span {
display: none;
}
#n1 {
left: 0;
width: 73px;
}
#n2 {
left: 74px;
width: 94px;
}
#n3 {
left: 167px;
width: 124px;
}
#n4 {
left: 292px;
width: 82px;
}
#n5 {
left: 375px;
width: 125px;
}
#n1 a:hover {
background: transparent url('../gfx/nav.gif') 0 -23px no-repeat;
}
#n2 a:hover {
background: transparent url('../gfx/nav.gif') -74px -46px no-repeat;
}
#n3 a:hover {
background: transparent url('../gfx/nav.gif') -167px -69px no-repeat;
}
#n4 a:hover {
background: transparent url('../gfx/nav.gif') -292px -92px no-repeat;
}
#n5 a:hover {
background: transparent url('../gfx/nav.gif') -375px -115px no-repeat;
}
And the HTML:
<ul id="nav">
<li id="n1"><span>Home</span></li>
<li id="n2"><span>About</span></li>
<li id="n3"><span>Programmes</span></li>
<li id="n4"><span>Grants</span></li>
<li id="n5"><span>Publications</span></li>
</ul>
So how do I make the background sprite shift for the entire nav, vertically different amounts depending on which link is hovered over? Assuming this is possible without JS of any sort.
Thanks. :)
PS - As requested, current system presented on a jsfiddle - http://jsfiddle.net/NhL7E/
Note how the edges of each coloured link don't completely change on the hover - hence wanting to move the entire UL background as opposed to individual LI backgrounds.
ADDED AFTER MARKED AS ANSWERED
Thank you to Shive, Jcubed and Barry Dowd. All three responses were completely acceptable and each one of them achieved the target result. However the primary question still is truly unanswered - as no one has suggested an HTML/CSS only method to shift the entire background image sprite different increments, based on which link is hovered on.
If I could mark all three answers as accepted, I would. I chose to mark Barry's as this is the answer that was easiest to implement on my project. It required no graphical modification so I was able to use the existing sprite image. All answers had benefits over the others - less http requests by use of jQuery, smaller nav sprite by another and no JS/jQuery required... etc.
Once again thank you all - your responses, jsfiddles, answers... your time and effort in helping me is greatly appreciated!
Cas
Here you go:
You give each li a left and right margin of -4px (#n1 only add to right margin, #n5 only add to left margin)
You then need to add 8px to each li width (4px on the first and last)
Then add 4px to the left position of the li background image so -74px becomes -70px (leave the first as 0)
New CSS
#nav {
position: relative;
float: right;
background: url('http://i59.tinypic.com/25tapoi.jpg');
width: 498px;
height: 23px;
margin: 110px 2px 0 0;
border: 0;
padding: 0;
}
#nav li {
position: absolute;
top: 0;
margin: 0 -4px;
border: 0;
padding: 0 0px;
list-style: none;
}
#nav li#n1 {
margin: 0 -4px 0 0;
}
#nav li, #nav a {
height: 23px;
display: block;
}
#nav span {
display: none;
}
#n1 {
left: 0;
width: 77px;
}
#n2 {
left: 74px;
width: 102px;
}
#n3 {
left: 167px;
width: 132px;
}
#n4 {
left: 292px;
width: 90px;
}
#n5 {
left: 375px;
width: 129px;
}
#n1 a:hover {
background: transparent url('http://i59.tinypic.com/25tapoi.jpg') 0 -23px no-repeat;
}
#n2 a:hover {
background: transparent url('http://i59.tinypic.com/25tapoi.jpg') -70px -46px no-repeat;
}
#n3 a:hover {
background: transparent url('http://i59.tinypic.com/25tapoi.jpg') -163px -69px no-repeat;
}
#n4 a:hover {
background: transparent url('http://i59.tinypic.com/25tapoi.jpg') -288px -92px no-repeat;
}
#n5 a:hover {
background: transparent url('http://i59.tinypic.com/25tapoi.jpg') -371px -115px no-repeat;
}
JSFiddle http://jsfiddle.net/NhL7E/12/
2 Solutions:
First, you can change your image so that it has extra space between each section of the navigation and has a transparent background. http://i60.tinypic.com/sq3xjn.png
This allows you to make each li have its own background that changes on its own without it effecting how the other parts oft he nav look.
#nav {
position: relative;
float: right;
/*background: url('http://i59.tinypic.com/25tapoi.jpg');*/
width: 498px;
height: 23px;
margin: 110px 2px 0 0;
border: 0;
padding: 0;
}
#nav li {
position: absolute;
top: 0;
margin: 0;
border: 0;
padding: 0;
list-style: none;
}
#nav li, #nav a {
height: 23px;
display: block;
}
#nav span {
display: none;
}
#n1 {
left: 0;
width: 73px;
}
#n2 {
left: 71px;
width: 94px;
}
#n3 {
left: 167px;
width: 124px;
}
#n4 {
left: 292px;
width: 82px;
}
#n5 {
left: 375px;
width: 125px;
}
#n1 a{
width:77px;
background: transparent url(http://i60.tinypic.com/sq3xjn.png) 0 0 no-repeat;
}
#n1 a:hover{
background-position:0 -23px;
}
#n2 a{
width:102px;
background: transparent url(http://i60.tinypic.com/sq3xjn.png) -77px 0 no-repeat;
}
#n2 a:hover{
background-position:-77px -23px;
}
#n3 a{
width:131px;
background: transparent url(http://i60.tinypic.com/sq3xjn.png) -179px 0 no-repeat;
}
#n3 a:hover{
background-position:-179px -23px;
}
#n4 a{
width:89px;
background: transparent url(http://i60.tinypic.com/sq3xjn.png) -310px 0 no-repeat;
}
#n4 a:hover{
background-position:-310px -23px;
}
#n5 a{
width:128px;
background: transparent url(http://i60.tinypic.com/sq3xjn.png) -399px 0 no-repeat;
}
#n5 a:hover{
background-position:-399px -23px;
}
http://jsfiddle.net/gh6Aq/
The other options is to nest your li's in such a way that the element with the background image is the deepest element, then you can use hover states to change it's style.
Example:
<ul id="nav">
<li id="n1"><span>Home</span>
<li id="n2"><span>About</span>
<li id="n3"><span>Programmes</span>
<li id="n4"><span>Grants</span>
<li id="n5"><span>Publications</span>
<div class='backgroundElement'></div>
</li>
</li>
</li>
</li>
</li>
</ul>
Then:
#n1:hover .backgroundElement{
background: transparent url('http://i59.tinypic.com/25tapoi.jpg') 0 -23px no-repeat;
}
However this method basically kills the underlying structure of your navigation, so I would recommend using the first option.
As continued from comments, I am posting a jQuery(JavaScript) based solution because, the exact problem is that, we have background image on the ul and we are hovering over ul>li>a and there is no parent selector in CSS to manipulate parent elements's CSS property(baclground image of ul).
However using jQuery we can easily achieve it. So the jQuery code will be something like this.
$('#nav >li>a').on('mouseenter', function() {
var id = $(this).parent().attr('id');
switch (id) {
case 'n1':
$(this).parent().parent().css({
'background-position': '0 -23px'
});
break;
case 'n2':
$(this).parent().parent().css({
'background-position': '-0 -46px'
});
break;
case 'n3':
$(this).parent().parent().css({
'background-position': '0 -69px'
});
break;
case 'n4':
$(this).parent().parent().css({
'background-position': '0 -92px'
});
break;
case 'n5':
$(this).parent().parent().css({
'background-position': '0 -115px'
});
break;
}
}).on('mouseout', function() {
$(this).parent().parent().css({
'background-position': '0 0'
});
});
Here the benefit we get is that the background image is now loaded only once and not 5 times because each time someone hovered over the image previously was getting loaded again.
Here we just find the ID of the hovered element and re-position the ul's background image accordingly.
You will also not need the additional code for :hover in the CSS, so the CSS code will be something like this.
#nav {
position: relative;
float: right;
background: url('http://i59.tinypic.com/25tapoi.jpg');
width: 498px;
height: 23px;
margin: 110px 2px 0 0;
border: 0;
padding: 0;
}
#nav li {
position: absolute;
top: 0;
margin: 0;
border: 0;
padding: 0;
list-style: none;
}
#nav li, #nav a {
height: 23px;
display: block;
}
#nav span {
display: none;
}
#n1 {
left: 0;
width: 73px;
}
#n2 {
left: 74px;
width: 94px;
}
#n3 {
left: 167px;
width: 124px;
}
#n4 {
left: 292px;
width: 82px;
}
#n5 {
left: 375px;
width: 125px;
}
JSFiddle Sample
Related
I am trying to implement background image sprite hover effect from this CSS-tricks article: http://css-tricks.com/fade-image-within-sprite/
My problem is that the images do not align completely in the following case:
HTML:
<ul class="contact">
<li class="phone"><a class="bg_hover" href="#">Call me</a>
</li>
<li class="twitter"><a class="bg_hover" href="#">Follow me on Twitter</a>
</li>
<li class="email"><a class="bg_hover" href="#">Email me</a>
</li>
</ul>
CSS:
.bg_hover {
position: relative;
}
.bg_hover:after {
content:"";
background-image: inherit;
background-position: bottom left;
background-repeat: no-repeat;
opacity: 0;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
transition: 1s;
}
.bg_hover:hover:after {
opacity: 1;
}
.contact {
margin-left: 60px;
}
.contact li {
float:left;
margin: 30px 15px 0 0;
font-style: italic;
}
.contact li a {
padding: 3px 0 0 25px;
height: 18px;
background-repeat: no-repeat;
display: block;
}
.contact .phone a {
background-image: url(http://i.imgur.com/9d9hdiL.png);
}
.contact .email a {
background-image: url(http://i.imgur.com/9d9hdiL.png);
}
.contact .twitter a {
background-image: url(http://i.imgur.com/9d9hdiL.png);
}
li {
list-style: none;
}
jsfiddle: http://jsfiddle.net/47Lngd4t/2/
Can you tell me where is the problem?
Your background-position isn't quite right. The image sprite you used is a pixel or two out. Change background-position to the following:
.bg_hover:after {
background-position: 0 -21px;
}
See demo here: http://jsfiddle.net/AndyMardell/47Lngd4t/3/
I changed
.contact li a {
padding: 3px 0 0 25px;
...
}
to
.contact li a {
padding: 2px 0 0 25px;
...
}
So, from 3px to 2px. Seems to align for me.
If You're talking about effect like here http://take.ms/a6ar2 simply add line-height for example 10px to .contact li a selector
There are also some other ways to get effect:
You can change padding of <a> elements
You can change background-position of image
I'm looking for a solution to group html elemts with a background. The real problems are the rounded corners highlighted in the picture. Is there a way to achieve this?
This solution still needs some work, but it's pretty close.
FIDDLE
Basically, I add a pseudo element before each list item using nth-child to group them with a particular color.
Also I set a lower z-index for each group.
I might be possible to play with the clip property to perfect this.
Markup
<ul>
<li></li><li></li><li class="last"></li>
<li></li><li></li><li></li><li></li><li></li><li class="last"></li>
<li></li><li></li><li></li><li class="last"></li>
</ul>
CSS
ul
{
list-style:none;
width: 350px;
}
li:before
{
content: '';
border-radius: 10px;
display: inline-block;
position: absolute;
top: -10px;
left: -10px;
height:70px;
width: 80px;
z-index:-1;
}
li:nth-child(-n+3):before
{
background: brown;
z-index: -2;
}
li:nth-child(n+4):nth-child(-n+9):before
{
background: green;
z-index: -3;
}
li:nth-child(n+10):nth-child(-n+13):before
{
background: pink;
z-index: -4;
}
li
{
width: 50px;height: 50px;
background: black;
border-radius: 10px;
margin: 5px 5px 10px 5px;
display: inline-block;
position:relative;
}
.last:before
{
z-index: -1!important;
width: 70px;
}
.last + li:before
{
border-radius: 10px 10px 10px 0;
}
/* clip the last item in each row */
li:nth-child(5n):before
{
width: 70px;
}
I'm building a navigation menu where I use a regular ul#nav.
In my example bellow I'm trying to make the div inside the li#third hang over the bottom of the ul#nav. I know I need to use position: absolute on the div inside li#third but if I do that then it just takes up the 100% of the width assigned to it.
I tried changing the position: absolute; width: 40%; on the div but then the last li slides under it.
How can I keep the width the same as the li#third element and still have it flow over it at the bottom?
Updated example: http://jsfiddle.net/VyHJR/24/
HTML :
<ul id="nav">
<li id="first">item</li>
<li id="second">item</li>
<li id="third"><div id="search">search</div></li>
<li id="fourth"><div id="flag"><div id="flag_item">4</div></div></li>
</ul>
CSS :
ul#nav { width: 600px; background-color: #fdd; padding: 0; margin: 30px 0 0 20px; overflow: hidden; }
ul#nav li { float: left; text-align: center; }
ul#nav li a { color: #333333; }
ul#nav li#first { background-color: #dff; width: 20%; padding: 6px 0; }
ul#nav li#second { background-color: #ddf; width: 20%; padding: 6px 0; }
ul#nav li#third { background-color: #dfd; width: 40%; }
ul#nav li#fourth { background-color: #ffd; width: 20%; }
li#third div#search { width: 100%; background-color: #333333; height: 40px; color: #ffffff; }
li#fourth div#flag { width: 100%; height: 20px; background-color: #333333; }
li#fourth div#flag div#flag_item { width: 1px height: 30px; background-color: red; }
See: http://jsfiddle.net/thirtydot/VyHJR/34/
Now I understand what you were trying to do, it makes sense.
I removed overflow: hidden on ul#nav, which I assume was there to contain the floats, and replaced it with display: inline-block. I could also have used clearfix.
I added position: relative; height: 1px; to ul#nav li#third. Some height was required, otherwise the fourth li takes the place of the third. position: relative to contain the absolutely positioned div#search.
I added left: 0 to div#search purely to fix IE7.
li{ overflow: hidden;
position: relative;}
I'm playing with 3 images. and it's making me dizzy. What I want is when a tab is active it will change the background-image.
I have this code right now in my html:
div id="promo-nav-wrapper">
<ul>
<li id="active">
</li>
<li>
</li>
</ul>
</div>
My CSS
#promo-nav-wrapper {
background: url("http://imageshack.us/photo/my-images/580/menubackground.png/");
background-repeat: repeat-x;
width: 100%;
height: 82px;
}
#promo-nav-wrapper ul {
text-align: center;
}
#promo-nav-wrapper ul li {
display: inline-block;
margin-top: 20px;
}
#promo-nav-wrapper ul li a {
height:53px;
width:41px;
display:block;
text-decoration: none;
background-repeat: no-repeat;
text-shadow: none;
}
a.promo-call{
background-image:url("http://imageshack.us/photo/my-images/861/callicon2.png/");
z-index: 3;
margin-right: 10px;
}
a.promo-text {
background-image:url("http://imageshack.us/photo/my-images/807/texticon2.png/");
margin-left: 10px;
margin-right: 10px;
}
/*this don't work*/
#promo-nav-wrapper li#active a {
background-image: url('http://imageshack.us/photo/my-images/694/selectediconbackground.png/') no-repeat!important;
height: 76px;
width: 64px;
/*background: blue;*/
}
My problem is I can't snip the image when an li is active, it doesn't show the background. T_T. Say like this
#active a{ background-image: url('selected_icon_background.png');
....
}
Acc to what i am understanding after reading the problem -
First of all in fiddle: http://jsfiddle.net/si_dean_ako/kyYWU/ images are not loading and secondly the css rule is wrong on #promo-nav-wrapper li#active a
Try to remove
#promo-nav-wrapper li#active a {
background-image: url('http://imageshack.us/photo/my-images/694/selectediconbackground.png/') no-repeat!important;
height: 76px;
width: 64px;
/*background: blue;*/
}
and add like this
#promo-nav-wrapper li#active {
background: url('http://imageshack.us/photo/my-images/694/selectediconbackground.png/') no-repeat!important;
height: 76px;
width: 64px;
}
When we want to write multiple value (shorthand properties) at that time we have to use background property of css and in above fiddle background-image is used and on that the url('image path'), no-repeat, !important; is applied. And background-image always take the path of the image.
So it better to use like that background: url('http://imageshack.us/photo/my-images/694/selectediconbackground.png/') no-repeat!important;
See updated fiddle: http://jsfiddle.net/kyYWU/2/ in this fiddle active image is showing behind the .
See the output generated on my local machine:
Try this
#promo-nav-wrapper #active a { background-image: url('selected_icon_background.png');
....
}
at the end of your stylesheet
I am making a navigation bar using <ul>. The css code is following:
.nav {
list-style: none;
background: url(/images/nav.png) no-repeat;
width: 666px;
height: 60px;
}
.nav li {
font-size: 0px;
background: url(/images/nav.png) no-repeat;
width: 120px;
height: 60px;
display: block;
float: left;
position: relative;
}
.nav .navhome {
background-position: -31px 0;
left: 31px;
}
.nav .navA {
background-position: -152px 0;
left: 32px;
}
.nav .navB {
background-position: -273px 0;
left: 33px;
}
.nav .navC {
background-position: -394px 0;
left: 34px;
}
.nav .navD {
background-position: -515px 0;
left: 35px;
}
.nav .navhover {
background-position-y: -60px;
}
.nav .navcurrent {
background-position-y: -120px;
cursor: default;
pointer-events: none;
}
There is also jQuery function that when the mouse hovers on one button, a class .navhover is added, so that the background image will be move up, and thus show a different part of the entire image; so is class .navcurrent (the current page).
I implemented it on MAC and tested it in Chrome. But when I validated the code I found that background-position-y is not standard (in fact, I also used background-position-x for those 5 buttons). Since there is x-offset for each button, background-position: 0 -60px for .navhover will always show the first one. Also, I tried background-position: inherit -60px; and it doesn't work. So how to only vertically move the background position?
Another question, pointer-events is also not standard, and it doesn't work in firefox and opera. Is there an alternative way to disable the click function on the button with class .navcurrent?
To prevent click event on .navcurrent:
$(".navcurrent").click(function(e) {
e.preventDefault();
});
and for the background position, why can't you have instances for each class:
.nav .navD:hover {
background-position: -515px -60px;
}