What is the best (as in cross-browser) technique to do image replacement in CSS? I am using sprites to do my navigation, but I want the markup to remain SEO friendly. Given the following HTML structure...
<div id="menu">
<ul>
<li>Test</li>
<li>Tester</li>
<li>Testing Testing</li>
</ul>
</div>
What is the best way to replace the text with a background image using CSS only?
I am currently using this...
text-indent: -9999px;
But, it fails with CSS on, and images off.
If this is the html:
<div id="menu">
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</div>
And this is the css:
#menu ul li a{
display: block;
overflow: hidden;
text-indent: -9999px;
background: transparent url(yourpicture.png) no-repeat 0 0;
width: 100px;
}
#home{
background-position: 0px 0px
}
#about{
background-position: -100px 0px
}
#contact{
background-position: -200px 0px
}
The image would then be 300px wide, and each tab would be 100px wide.
In 2008, Google's presentation at An Event Apart made it clear that valid image replacement will not be penalized by Google. See Mezzoblue's post about it
Basically, as long as the image you replace the text with has the same text in it, it will be considered valid and not trying to cheat search engines. How do they determine whether the image is valid or not? I have no idea... OCR? Manual review?
As far as CSS on/images off, there is no perfect solution, all of them require extra non-semantic markup. See the css-tricks link that beggs posted on the different techniques. I personally do not bother with the very small percentage of users who browse with CSS but no images.
Your choice is simple. Extra markup, or don't care about css on/images off.
The background image is usally applied to the <a> link, giving the entire clickable area an image. To hide the text you can use a very big negative value for text-indent.
I just came up with this, it seems to work in all modern browsers, I just tested it then on (IE8/compatibility, Chrome, Safari, Moz)
HTML
<img id="my_image" alt="my text" src="images/small_transparent.gif" />
CSS
#my_image{
background-image:url('images/my_image.png');
width:100px;
height:100px;}
Pro's:
image alt text is best-practice for accessibility/seo
no extra HTML markup, and the css is pretty minimal too
gets around the css on/images off issue where "text-indent" techniques still hide text for low bandwidth users
The biggest disadvantage that I can think of is the css off/images on situation, because you'll only send a transparent gif.
It might be possible to write a little javascript to help out with this, replacing all the image sources with their background-image css properties. But this would only work if the browsers still attaches css properties to elements and then ignores them. I don't know if this is the case or not, I'll have to test it out. You'd also want to develop a javascript-based test to see if css is being applied to the page (maybe check the position of some test element).
btw, I'd like to know, who uses images without stylesheets? some kind of mobile phone or something?
edit:
Based on comment below... inline styles hrm... maybe I should just make a php helper function like <?php echo css_image('image_id','my text','image_url');?> to generate some code like this:
HTML
<div id="image_id" style="background-image:url('image_url')" class="image">
<img src="image_url" class="alt_text" alt="my text" />
<p>my text</p>
</div><!--/#my_image-->
then just attach some CSS in the stylesheet
#image_id{width:*image width*;height:*image height*}
.alt_text{position:absolute;top:0px;left:0px}
.image{display:block;background-position:left top}
.image p{position:absolute;left:-9999em}
it's an older technique that I'm using, not sure where I found it though. It works with CSS on/images off, CSS off/images on, CSS on/images on.
If a user with CSS off/images off visits, they'll see doubled up text. If a search engine spider visits, they'll see alt text and regular text, an intelligent spider could easily identify this for what it is, an innocent image replacement technique.
So, this technique is worst for screen readers, since alt text is read, but these users should be able to skip to the next paragraph, which is why I stuck <p></p> around "my text".
Everyone else with both CSS and images turned off is some kind of bot, right?
#menu ul li a {
display: block;
background-image: url(images/someimage.png);
text-indent: -9000px;
width: 454px;
height: 64px;
}
The display:block is important or else your width and height may not look right.
This is the code I use for replacing logo text with an image while keeping the text in the code but not shown to the user (this is Google approved). View the completed example here:
http://discretiondesigns.com/overflow/imagereplacement/
Here's the full code (images can be found at the above link - images can be varying sizes - the entire image is clickable and changes upon hover):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Image Replacement</title>
<style type="text/css">
<!--
#menu li { list-style: none; }
#menu #a { font: .9em Verdana, Arial, Helvetica, sans-serif; color: #E9E7E0; height: 20px; width: 100px; padding-top: 8px; padding-left: 8px; float: left; }
#menu #a a { background: url(http://discretiondesigns.com/overflow/imagereplacement/a_off.gif) no-repeat left top; height: 20px; width: 100px; display: block; }
#menu #a a:hover { background: url(http://discretiondesigns.com/overflow/imagereplacement/a_on.gif); }
#menu #a span { display: none; }
#menu #b { font: .9em Verdana, Arial, Helvetica, sans-serif; color: #E9E7E0; height: 20px; width: 100px; padding-top: 8px; padding-left: 8px; float: left; }
#menu #b a { background: url(http://discretiondesigns.com/overflow/imagereplacement/b_off.gif) no-repeat left top; height: 20px; width: 100px; display: block; }
#menu #b a:hover { background: url(http://discretiondesigns.com/overflow/imagereplacement/b_on.gif); }
#menu #b span { display: none; }
#menu #c { font: .9em Verdana, Arial, Helvetica, sans-serif; color: #E9E7E0; height: 20px; width: 100px; padding-top: 8px; padding-left: 8px; float: left; }
#menu #c a { background: url(http://discretiondesigns.com/overflow/imagereplacement/c_off.gif) no-repeat left top; height: 20px; width: 100px; display: block; }
#menu #c a:hover { background: url(http://discretiondesigns.com/overflow/imagereplacement/c_on.gif); }
#menu #c span { display: none; }
-->
</style>
</head>
<body>
<div id="menu">
<ul>
<li id="a"><span>Nav A</span></li>
<li id="b"><span>Nav B</span></li>
<li id="c"><span>Nav C</span></li>
</ul>
</div>
</body>
</html>
This is touted to work no matter the settings of css/images:
http://www.tjkdesign.com/articles/tip.asp
CSS Tricks has one of the most detailed posts on the subject here
They show various techniques. The one that solves your problem of css on and images off is:
HTML:
CSS Tricks has one of the most detailed pages on the subject here
They show various techniques. The one that solves your problem of css on and images off is the technique #8:
HTML:
<div id="menu">
<ul>
<li><span></span>Test</li>
<li><span></span>Tester</li>
</ul>
</div>
CSS:
#menu a {
width: 350px; height: 75px; /*your values here*/
position: relative;
}
#menu a span {
background: url("images/li.jpg"); /*your image here*/
position: absolute;
width: 100%;
height: 100%;
}
EDIT: Updated the code to the sample provided.
PS: I didn't test the code above.
CSS:
#menu ul li a{
display: block;
background-image: url(http://example.com/sprite.png);
width: 100px;
height: 50px;
}
#a {
background-position: <offset for sprite>;
}
#b {
background-position: <offset for sprite>;
}
#c {
background-position: <offset for sprite>;
}
HTML:
<div id="menu">
<ul>
<li id="a">Test</li>
<li id="b">Tester</li>
<li id="c">Testing Testing</li>
</ul>
</div>
Edit: added the link text back in... 'cause it was missed. :-)
Related
I ran into one IE-specific problem that I just can't wrap my head around.
The following HTML and CSS can be seen live in this pen.
:: HTML
<div id="container">
<div class="dummy">Dummy</div>
<nav>
<div id="right">
<ul>
<li>Lorem ipsum <img src="http://placehold.it/80x40"> dolor sit amet.</li>
<li>Anal natrach, ut vas petat, <img src="http://placehold.it/80x40"> doriel dienve.</li>
</ul>
<div class="dummy">Dummy</div>
<div class="dummy">Dummy</div>
</div>
</nav>
</div>
:: CSS
/* RESET */
* { margin: 0; padding: 0; vertical-align: top; }
ul { list-style: none; }
/* MARKUP */
#container {
line-height: 0;
font-size: 0rem;
text-align: justify;
text-justify: distribute-all-lines;
}
#container:after {
content: '';
display: inline-block;
width: 100%;
}
#container > * {
display: inline-block;
line-height: 1;
font-size: 1rem;
text-align: left;
text-justify: none; /* does not work */
}
#container nav {
text-align: right;
}
#right > * {
display: inline-block;
}
/* COLORS & STUFF */
#container { padding: 10px; background: #cfc; }
.dummy { padding: 10px; background: #ffc; }
#container nav { padding: 10px; background: #ccf; }
ul { padding: 10px; background: #fcc; }
So, what's the Problem?
The content of the green div is justified, while each child of the very div in turn is given text-align: left;. Those children are: the left dummy div and the bluish nav.
The nav contains a list (red), and two dummies. For the red list's items the text-align is set to right - and there's lies the problem (or at least, there you can see it).
The first image is shifted to the left (and thus overlays/hides some piece of the text). The second image (and thus the whole second list item) is fine. This, however, changes, when changing the text. It seems as if only the image of the longest (meaning widest) item stays where it should be - all other images (if you were to create some more items) are shifted - depending on the list item's width, that is.
Now, why is that so - and how can I fix it?
The following things I found out so far:
When setting the li { text-align: left; } the image stays fine in between the two text portions - but I don't get right alignment, of course.
When removing text-justify from the #container the image stays fine as well.
Setting text-justify either to auto or to none does not seem to work...
Once again: this is just regarding Internet Explorer (9+).
// EDIT
In order to avoid your time being spent on something I'm not interested in, I'll post something more on what I'd like to have.
The final code must
keep the current/desired functionality (i.e., justified alignment);
work in all major browsers (current version and at least one before that).
The final code must not
contain floats;
contain absolute/relative positions.
// EDIT
Here is a screenshot of the desired result (Firefox), and one of what I get in IE...
Change your text-justify to distribute (Tested in IE10, IE9, Chrome, FF):
text-justify: distribute;
Check out the codepen to see it in action.
Did you try by setting like this?
li img{display: inline-block; margin: 0 5px;} /*you could set margin: 1px; only*/
your code pen
I've looked everywhere for a solution to this so I don't really expect it to be simple.
I want to display an icon with an overhead text label. I'd like the text to respond to hover, whether the cursor is positioned over the text OR over the icon image.
The closest example I can find is at this link http://www.sencha.com/forum/showthread.php?122028-Label-with-icon
which gives the following CSS solution:
Label l = new Label("My Text");
l.addStyleName("my-label");
#CSS
.my-label {
background:url(my-icon.png) no-repeat right center;
padding-right:20px;
}
But my CSS skills aren't good enough - I haven't had much success in adapting this to an above-centered label instead of a centered label to the left of the icon image.
Would anyone like to give it a shot for me?
Additional Info:
Here's what I have now - which isn't working, the "display: block; doesn't seem to let me use a background-img attribute ...
CSS:
.blogicon {
width: 70px;
text-align: center;
background-img:url("http://dispatchesusa.typepad.com/the_dov_blog/link-images/bookmark.png") no-repeat bottom center;
display: block;
padding-top: 4px;
padding-bottom: 90px;
}
HTML:
/* <h6 class="blogicon">Blog</h6> */
If you want to display the text above the icon, You can change the CSS to be:
.my-label {
background:url(my-icon.png) no-repeat bottom center;
padding-bottom:20px; /* this should be >= the icon's height */
}
It would be better if we could see your HTML, too, or at least a screen shot of what you are picturing, but this should be pretty easy. You can either wrap an <a> around the text and icon and set :hover rules, or you could add the text via the :before pseudo element to the <a>, which can be styled for both hover and non-hover states.
EDIT:
Now that we have a better idea of what you want, here's how you could do it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
.blogicon {
width: 70px;
text-align: center;
backgrond: #f7f7f7;
padding-top: 4px;
}
.blogicon a {
display: block;
background:url("http://dispatchesusa.typepad.com/the_dov_blog/link-images/bookmark.png") no-repeat 50% 100%;
padding-bottom: 90px;
color: blue;
text-decoration: none;
font-weight: bold;
}
.blogicon a:hover, .blogicon a:focus {
color: red;
}
</style>
</head>
<body>
<div class="blogicon">Blog</div>
</body>
</html>
I have taken the liberty to change <h6> to <div>, as this probably is not a true heading. But of course, you can change this back if you want, but it's rare to need an <h6>, so I suspect you are using it for presentational reasons, which is to be avoided. It's easy enough to set the font-weight of the link to bold, as shown.
I have major issues with cross browser compatibility. This picture illustrates the problem:
What code do I put in for IE7-8 so that my menu aligns properly? Right now it looks right in firefox but nothing else.
This the the menu code she had (there might be other code associated but I don't know, see actual site):
.custom .menu {
height:25px;
border: 1px none;
float:right;
}
I have tried things mentioned in other threads, overflow:hidden; / giving a width / margin: 0 auto etc. Nothing works and only ends up breaking Firefox as well.
Try
.custom .menu {
height: 106px;
border: 0px none;
float: right;
}
.custom #header {
background: transparent;
height: 80px;
top: -80px;
position: relative;
border-bottom: 0;
}
Based on what I see in Safari on Mac, which looks similar to the problem you've got. There are a few css issues.
#header { float:left; }
.menu-menu-top-container { float:right; }
remove:
#header { clear:both; }
.custom .menu { height:25px; }
There are a lot of issues with this site though. I'd personally start all over with both html and css. It's one of the stranger pieces of code I've seen in a long time.
You have HTML issues that are likely the cause. Explorer, for example, hates invalid HTML and has the hardest time figuring out your intent. Other browsers make different guesses, and your site is also broken in Safari. Point being, unless you follow the standards, rendering will be unpredictable.
You have two empty <ul> elements which is not valid.
<ul> requires <li>
<div id="sidebar_1" class="sidebar">
<ul class="sidebar_list">
</ul>
</div>
<div id="sidebar_2" class="sidebar">
<ul class="sidebar_list">
</ul>
</div>
Once you fix the HTML, only then work on your CSS issues.
I have been researching how to use CSS sprites as image links, but I can't figure this out. I have a PNG (here: ) that has two images in it (for simplicity). I want each image to be act as an icon that can be linked to an external website (Twitter and Facebook). I set up my CSS like this:
CSS
#authorpage-links ul {
list-style-type:none;
}
#authorpage-links ul li {
background: url("/links-authorpage1.png") no-repeat scroll 0 0 transparent;
}
#authorpage-links ul li.twitter {
background: url("/links-authorpage1.png") no-repeat 0 0;
width: 20px;
height: 14px;
}
#authorpage-links ul li.facebook {
background: url("/links-authorpage1.png") no-repeat -21px 0;
width: 14px;
height: 14px;
}
...and my HTML like this:
HTML
<ul id="authorpage-links">
<li id="authorpage-links" class="twitter">
<a target="_blank" href="http://twitter.com/"></a>
</li>
<li id="authorpage-links" class="facebook">
<a target="_blank" href="http://facebook.com/"></a>
</li>
</ul>
Now, 2 questions:
1) Is using a list to display these images the best way or should I use div's?
2) Is this an issue with my CSS IDs and classes?
Any help is greatly appreciated.
Based on a revision of your CSS (problems that I'll come to, later) to the following:
#authorpage-list {
list-style-type: none;
}
#authorpage-list li {
float: left;
}
#authorpage-list li a {
background-color: transparent; /* I broke the background down into individual parts */
background-image: url(http://i.stack.imgur.com/ta3Va.png);
background-position: 0 0;
background-repeat: no-repeat;
width: 15px;
height: 15px;
display: block; /* in order that the a elements could be assigned a width/height */
border: 1px solid #f90; /* for diagnostic purposes while working on this, adjust to taste */
}
#authorpage-list #authorpage-facebook-link a {
/* a specific selector, in order to be more specific than the previous
selector which styled the defaults for the a elements in this position */
background-position: -21px 0;
}
And amending your HTML to the following:
<ul id="authorpage-list">
<li id="authorpage-twitter-link" class="twitter">
<a target="_blank" href="http://twitter.com/"></a>
</li>
<li id="authorpage-facebook-link" class="facebook">
<a target="_blank" href="http://facebook.com/"></a>
</li>
</ul>
I came up with this: JS Fiddle demo.
CSS problems
This is the biggest no-no insofar as HTML goes (or so far as I've ever been able to see, it's even worse than the blink tag): you have multiple examples of the same id in your HTML. An id must be unique within the document. If not, you have invalid HTML. Which causes problems with CSS, with JavaScript and...it's just bad.
If you have multiple elements that need to share a property/style, or whatever, use a class, not an id.
Your selectors. #authorpage-links ul should match a ul element within an ancestor element of id="#authorpage-links". The ul is the element with that id. I'll ignore that its child elements also had that id, since I think I've covered that part. All your other CSS started off that base, which wasn't accurate, and so didn't work.
Your <li> elements may be sized to 14x14, but you've got nothing in the <a> tags, so those'll shrink down to a 0x0 area, effectively making your list elements clickable areas invisible. You should probably put a space into the anchor tag, so there's SOMETHING to push them open, e.g.
<a target="_blank" href="http://facebook.com/"> </a>
^^^^^^
Your a link need to have a size. I did so in making the a's have a clickable area. Since your lis don't need a size i gave the size to the a links.
Replace your li css with:
ul#authorpage-links li a {
display: inline-block;
background: url("/links-authorpage1.png") no-repeat scroll 0 0 transparent;
}
ul#authorpage-links li.twitter a {
background-position: 0 0;
width: 20px;
height: 14px;
}
ul#authorpage-links li.facebook a {
background-position -21px 0;
width: 14px;
height: 14px;
}
Also remove the id attribute from your lis.
"... fantastic answer ..." - Sparky672
I'm trying to design a website for my mums backpackers business. The problem that I am having is between my banner image and my navbar there is a blank white line that you can see in the image. I thought this is to do with the margin so I have set it to zero for both of the elements to no avail.
Also a second question - Why does my black border not cover the main content as well? I thought since its a body background it would go around every element in the body.
I realise there may have been similar questions but I can't find the answer anywhere. I will appreciate anyones input - this is my first post here so I'm sorry if I screwed up any formatting.
The image of my website can be found here:
http://postimage.org/image/20dhjcdb8/
Thanks in advance.
I currently have the following code in my index.html file:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<link rel="stylesheet" type="text/css" href="swaggersstyle.css">
<title>Oamaru Backpackers Hostel, Swaggers Backpackers - Home</title>
</head>
<body>
<img src="final.jpg" id="banner"></img>
<ul id="nav">
<li class="links">Home</li>
<li class="links">Planning</li>
<li class="links">Construction</li>
<li class="links">Evaluation</li>
</ul>
<div id="mainc">
<p>Make Yourself at Home</p>
<p>Swaggers Backpackers is a converted old house located within walking distance of all the best parts of Oamaru. Explore the old victorian era buildings and shops of the city centre, or see the penguin colonies down the street. Swaggers is owned and operated by camp mum Agra, who makes all guests feel welcome, informed, and perhaps a bit mothered. </p>
</div>
</body>
</html>
and the following CSS code:
html{
font-family: sans-serif;
background-color:#464E54;
}
body{
width: 960px;
margin: auto;
background-color: white;
border: 5px solid black;
}
#banner{
padding: 0px;
margin: 0;
}
#nav {
list-style-type: none;
padding: 0px;
margin: 0px;
overflow: hidden;
}
#mainc {
width: 960px;
float: right;
background-color: white;
margin: 0;
}
.links {
float: left;
margin: 0px;
}
a:link, a:visited {
display: block;
width: 232px;
font-weight: bold;
color: grey;
background-color: #dad8bf;
text-align: center;
padding: 4px;
text-decoration: none;
text-transform: uppercase;
margin-top: 0px;
}
a:hover, a:active{
background-color: #333333;
}
The problem that I am having is between my banner image and my navbar there is a blank white line that you can see in the image. I thought this is to do with the margin so I have set it to zero for both of the elements to no avail.
In HTML images are by default inline level elements so they follow text rules (and will have blank space below to keep the correct alignment with letters like "p" and such). You can either assign display: block to the header image, or define the header container to have the same exact height as the image
Also a second question - Why does my black border not cover the main content as well? I thought since its a body background it would go around every element in the body.
Because floated elements pop out of their container, you have to clear the float to extend the container with something like
<div style="clear: both"></div>
or use some reset/clearfix css such as the one provided by html5boilerplate.
add to your css
#banner { display: block; }
If you remove the float property of #mainc then the border will surround all the content. By using float, you are taking the div out of the main page flow.