align icons with text - css

What's the best way to align icons (left) and text (right) or the opposite text on left and icon on right?
Does the icon image and text have to be the same size? Ideally I would like them to be different but be on the same vertical alignment.
I am using background-position css property to get the icons from a larger image.
Here is how I do it now, but I am struggling with either getting them to be on the same line or be vertically aligned to the bottom.
Text
This is what I get after I try your suggestions.
Though the text is now aligned with the icon, it is superimposed over the icon to the right of the icon that I want. Please note that i am using the background position to show the icon from a larger set of images.
Basically I am getting
<icon><10px><text_and_unwanted_icon_to_the_right_under_it>
<span class="group3_drops_icon group3_l_icon" style="">50</span>
group3_drops_icon {
background-position:-50px -111px;
}
.group3_l_icon {
-moz-background-clip:border;
-moz-background-inline-policy:continuous;
-moz-background-origin:padding;
background:transparent url(/images/group3.png) no-repeat scroll left center;
height:35px;
overflow:hidden;
padding-left:55px;
}

I usually use background:
<style type="text/css">
.icon {
background-image: url(path/to/my/icon.jpg);
background-position: left center;
background-repeat: no-repeat;
padding-left: 16px; /* Or size of icon + spacing */
}
</style>
<span class="icon">Some text here</span>

You can do it on the same line using vertical-align and line-height
<p style='line-height: 30px'>
<img src='icon.gif' style='vertical-align: middle' />Icon Text
</p>
Alternatively, you can go the background approach with no-repeat and positioning:
span.icontext {
background: transparent url(icon.gif) no-repeat inherit left center;
padding-left: 10px /* at least the width of the icon */
}
<span class="icontext">
Icon Text
</span>

Sadly, neither of these answers are bullet proof and each have one big flaw.
#rossipedia
I used to implement all my icons this way and it works quite well. But, and this is a big but, it does not work with sprites, since you're using the background-position property to position the icon inside the container that includes your text.
And not using sprites where you can is bad for performance and SEO, making them imperative for any good modern website.
#Jamie Wong
The first solution has two markup flaws. Using elements semantically correctly is sadly underrated by some, but you'll see the benefits in prioritizing form in your search engine ranking. So first of all, you shouldn't use a p-tag when the content is not a paragraph. Use span instead. Secondly, the img-tag is meant for content only. In very specific cases, you might have to ignore this rule, but this isn't one of them.
My Solution:
I won't lie to you, I've checked in a lot of places in my time and IMHO there is no optimal solution. These two solutions are the ones that come closest to that, though:
Inline-Block Solution
HTML:
<div class="container">
<div class="icon"></div>
<span class="content">Hello</span>
</div>
CSS:
.container {
margin-top: 50px;
}
.container .icon {
height: 30px;
width: 30px;
background: #000;
display: inline-block;
vertical-align: middle;
}
.container .content {
display: inline-block;
vertical-align: middle;
}
"display:inline-block;" is a beautiful thing. You can do so much with it and it plays very nicely with responsive design.
But it depends on your client. Inline-Block does not work well with IE6, IE7 and still causes problems with IE8. I personally no longer support IE6 and 7, but IE8 is still out there. If your client really needs his website to be usable in IE8, inline-block is sadly no option. Assess this first. Replace the black background of the icon-element with your sprite, position it, throw no-repeat in there and voilà, there you have it.
Oh yeah, and as a plus, you can align the text any way you want with vertical-align.
P.S.: I am aware that there's an empty HTML-tag in there, if anyone has a suggestion as to how to fill it, I'd be thankful.
Fixed Height Solution
.clearfix:after {
content: ".";
display: block;
clear: both;
visibility: hidden;
line-height: 0;
height: 0;
}
.clearfix {
display: inline-block;
}
html[xmlns] .clearfix {
display: block;
}
* html .clearfix {
height: 1%;
}
.container {
margin-top: 50px;
border: 1px solid #000;
}
.container .icon {
height: 30px;
width: 30px;
background: #000;
float:left;
}
.container .content {
line-height: 30px;
float: left;
display: block;
}
I hate this one. It uses a fixed line height for the text, and if you choose the same height as the Icon's box, the text is centered to that height. To align the text to the top, cut the line height, and as to the bottom, you'll have to fix that with position: absolute and a fixed width and height for the container. I'm not going to get into that unless someone requests it, because it's a whole issue for itself, and brings with it a lot of disadvantages.
The main disadvantage of this path is the fixed height. Fixed heights are always unflexible and especially with text, it can cause a bunch of problems (You can no longer scale the text as a user without it being cut off, plus different browsers render text differently). So be sure that in no browser the text is cut off and that it has some wiggle room inside its line height.
P.S.: Don't forget the clearfix for the container. And, of course, replace the black background with your sprite and according position + no-repeat.
Conclusion
Use inline-block if at all possible. ;) If it's not, breath deeply and try the second solution.

Related

Vertical alignment based on x-height

When trying to center content in a container CSS-Tricks has a great guide. However when trying to vertically center some text that's just slightly smaller than its container, I think a different way of vertically centering text might be preferable. Instead of using the entire height of the font, I would rather center it based on the x-height of the font (basically the height of a lowercase x)
And see this example where red is based on the entire height and green is based on the x-height
The only option I could come up with is to add a pseudo element to the text with the same height as the container and to use vertical-align: middle to it.
.pseudo {
white-space: nowrap;
}
.pseudo:before {
content: '';
display: inline-block;
vertical-align: middle;
height: 100px;
width: 0;
}
This works, but unfortunately only for a single line. I was wondering if anyone else tried to solve this issue and if perhaps there are best practices to follow? I am especially interested using as little "magic" numbers as possible and if there is a good solution for the multi line variant.
See Codepen for an example on why I want to center it based on the x-height, and my solution.
The differece between text center position and the small letters center is equal to (ascender height - x-height - descender height)/2 (basically we need to increase somehow the descender height to make it equal to ascender height - x-height to move the geometric center of the line box to the position of the small letters center). From these 3 unknowns, only x-height is available for CSS (via ex unit). Other font metrics can't be read and remain kind of 'magical numbers', so it's possible only to choose the a specific value for each specific font. But with this 'font-specific magic number' you can center any number of lines - by giving the inner element display:inline-block and assigning the magic value to its padding-bottom.
It seems impossible to get the needed value from the font metrics in pure CSS. Such vertical-align values as text-top/text-bottom can give the position of ascender or descender, but only one of them, exotic values like sub seem to be completely arbitrary, and I found no possibility to 'measure' the difference between two font metrics for one element.
My most successful attempt was the way to move the line (or lines) by half of the needed difference, making 'hybrid' centering (neither caps nor lowercase letters are centerd precisely, but 'optically' the text may look even better centered). This can be done by another pseudo element added to the last line, that has the height of the line box, but its aligned with the center of small letters:
.blue:after {
content: ':'; /* must contain text to get the auto height of the line box */
display: inline-block;
vertical-align: middle;
width: 0; /* making pseudo elenent invisible */
overflow: hidden;
}
Edited CodePen example with the result (I didn't hide pseudo elements there for visualization).
For centering the inline-block itself, any approach can be used, I choose the approach with second helper pseudo element that always has 100% height of the container, so no more magic numbers are needed.
Hope it helps:)
Sorry can't comment.
How about this:
.green {
color: #6c6;
background-color: #cfc;
vertical-align: -16%;
line-height: 60px;
}
http://jsfiddle.net/hcn25psh/3/
and some info which might help:
http://www.w3schools.com/cssref/pr_pos_vertical-align.asp
I think the only way to get the wanted result is to use Dinamyc CSS (DCSS).
First, you will need to create a function in your website that will retrieve the height of the text (to lower case).
Second, you will need to output the css with a static position which is in reality dynamic since it is printed by your dynamic code.
Here an example pasted from this link http://www.phpsnaps.com/snaps/view/get-text-height-width/ on how to retrieve your text height in PHP :
define("F_SIZE", 8);
define("F_FONT", "arial.ttf");
function get_bbox($text){
return imagettfbbox(F_SIZE, 0, F_FONT, $text);
}
function text_height ($text) {
$box = get_bbox($text);
$height = $box[3] - $box[5];
return $height;
}
function text_width ($text) {
$box = get_bbox($text);
$width = $box[4] - $box[6];
return $width;
}
And then you would echo your (x)HTML with CSS somehow like that :
echo "<span style=\"YourStyleProperty=" . **Your line height / 2 + your text height / 2 (Hint: use the PHP or equivalent if other language)** . ";\"
For more information on the imagettfbbox function :http://php.net/manual/fr/function.imagettfbbox.php
Feel free to post if you are having trouble finalizing the code, I will be glad to help if you show some efforts :).
For more info on DCSS and maybe better ideas/example don't hesitate to google DCSS.
Use this css
.outer {
display: table;
width: 200px;
height: 200px;
background-color:blue;
}
.inner {
display: table-cell;
vertical-align: middle;
/*You can align center if you want as well*/
/*text-align:center;*/
}
.box {
position: relative;
display: inline-block;
background: orange;
color: black;
font-size: 60px;
background-color: yellow;
}
And use this markup. So whatever is in the "box" div will be centered.
So it is just about adding an outer to act as table and inner to act as cell so you can use the vertical align middle for multiple lines.
<div class="outer">
<div class="inner">
<div class="box">
Texty</br>
Texty
</div>
</div>
</div>
here is a codepen
Ilya Streltsyn's answer (the accepted one) is amazing. Exactly the kind of thing I like about CSS - if you know the mechanics well enough, you can accomplish anything.
I have generalized the accepted answer into a reusable class, tested on Chrome, Firefox and Edge. I have also fixed issues with how it sits in the document flow (the container would carry extra width from the ::after elements, and would appear lower than sibling elements). You can easily use the class as follows:
<any class="x-height">
<span class="x-height">
Centered text
</span>
</any>
And below is the Sass source (Also check it out on Codepen):
%x-height {
content: 'x';
display: inline-block;
vertical-align: middle;
width: 0;
}
.x-height {
vertical-align: bottom;
&::after {
#extend %x-height;
content: '';
height: 100%;
}
> .x-height {
display: inline-block;
vertical-align: baseline;
margin-left: -1ch;
margin-right: calc(-1ch / 2);
white-space: nowrap;
#at-root {
#-moz-document url-prefix() {
& {
margin-left: auto;
margin-right: auto;
&::before { display: none; }
}
}
}
&::before, &::after {
#extend %x-height;
visibility: hidden;
}
&::after {
width: 1ch;
margin: 0 -1ch;
}
}
}
You probably need one of these jQuery plugins:
FlowType: Web typography at its finest: font-size and line-height based on element width
Squishy: A plugin for fitting heading text to its container
Responsive Text: Set font sizes responsively based on its’ container width
TypeButter: Allows you to set optical kerning for any font on your website
FitText: FitText makes font-sizes flexible
SlabText: A jQuery plugin for producing big, bold and responsive headlines
Auto Line-Height: A jQuery plugin for flexible layouts

*Perfect* vertical image alignment

I have a square div of fixed size and wish to place an arbitrary size image inside so that it is centred both horizontally and vertically, using CSS. Horizontally is easy:
.container { text-align: center }
For the vertical, the common solution is:
.container {
height: 50px;
line-height: 50px;
}
img {
vertical-align: middle;
}
But this is not perfect, depending on the font size, the image will be around 2-4px too far down.
To my understanding, this is because the "middle" used for vertical-align is not really the middle, but a particular position on the font that is close to the middle. A (slightly hacky) workaround would be:
container {
font-size: 0;
}
and this works in Chrome and IE7, but not IE8. We are hoping to make all font lines the same point, in the middle, but it seems to be hit-and-miss depending on the browser and, probably, the font used.
The only solution I can think of is to hack the line-height, making it slightly shorter, to make the image appear in the right location, but it seems extremely fragile. Is there a better solution?
See a demo of all three solutions here:
http://jsfiddle.net/usvrj/3/
Those without IE8 may find this screenshot useful:
If css3 is an option, then flexbox does a good job at vertical and horizontal aligning:
UPDATED FIDDLE
.container {
display:flex;
align-items: center; /* align vertical */
justify-content: center; /* align horizontal */
}
How about using your image as a background? This way you could center it consistently everywhere. Something along these lines:
margin:5px;
padding:0;
background:url(http://dummyimage.com/50) no-repeat center center red;
height:60px;
width:60px;
This is REALLY hacky, but it is what we used to do in the ie6 days.
.container {
position: relative;
}
img {
position: absolute;
top: 50%;
left: 50%;
margin-top: -12px; // half of whatever the image's height is, assuming 24px
margin-left: -12px; // half of whatever the image's width is, assuming 24px
}
I may be missing something in this example, but you get the idea.
Have you tried the following:
img {
display: block;
line-height: 0;
}
I usually use this hack, but I haven't really checked it that thoroughly in IE8.
Here is a small JS Fiddle I have made: http://jsfiddle.net/rachit5/Ge4YH/
I believe it matches your requirement.
HTML:
<div>
<img src=""/>
</div>
CSS:
div{height:400px;width:400px;position:relative;border:1px solid #000;}
img{position:absolute;top:0;left:0;right:0;bottom:0;margin:auto;}

Placing an icon beside the text of an H1 tag by using a span

Here's the HTML I'm trying to use:
<h1>Order Not Paid<span class="not-paid"></span></h1>
Of course if there is a better way please say so.
Currently since there is no text inside of the span, it seems the browsers are ignoring this tag. Firebug shows up grayed out when inspecting.
When I place text in the span, the icon shows correctly.
What CSS rule can I apply for this effect? Here's what I have so far (It's SASS, but easy to grasp):
h1 {
font-size: 24px;
span.not-paid {
background-image: url('/Public/images/remove.png');
background-repeat: no-repeat;
}
}
I'd like the icon to appear where the span is.
Alternatively, is it kosher to do something like this? If so, I can settle with this as it looks good on IE8 and modern browsers.
<h1>Order Not Paid <img src="#Url.Content("~/Public/images/remove.png")" alt="" /></h1>
If the icon is small and not reused anywhere else just set it as part of the h1.
HTML:
<h1 class="not-paid">Order Not Paid</h1>
CSS:
h1.not-paid {
font-size: 24px;
padding:0 16px 0 0; /* whatever the dimensions the image needs */
background-image: url('/Public/images/remove.png') no-repeat right center; /* Position left/right/whatever */
}
A little cleaner this way.
the background image is not showing up because the span has no width, and therefore is not showing any of the background.
also, the snippet you gave is not valid css.
try something like this, assuming the image is 16px by 16px:
h1 {
font-size: 24px;
}
span.not-paid {
display: inline-block;
vertical-align: middle;
height: 16px;
width: 16px;
background-image: url('/Public/images/remove.png');
background-repeat: no-repeat;
}
The display: inline-block; is to make it so the width will apply. The vertical-align is to center the image on the middle of the line.
All of that said, the <img> tag solution would work too, but it doesn't scale well to a lot of similar images. The css-based solution makes it easier to switch to something like css spriting later.
In either case, you'll probably want to change your direct image urls to relative urls before expecting this page to work in a production environment.
I'm pretty sure that you need to give the span some width. By default it has none, so of course no background image will be seen.
First, if you are not using sass and less, your stylesheet is wrong. Next, give inner-block to span and the image height and width.
h1 {
font- size: 24px;
}
h1 span.not-paid {
width: 50px;
height: 50px;
display: inline-block;
background-image: url('/Public/images/remove.png');
background-repeat: no-repeat;
}

How can I make the width of my <figcaption> match the width of the <img> inside its <figure> tag?

Say, I got this code:
<figure>
<img src="bunnyrabbit.jpg" width="200" height="150" alt="An image of a bunny rabbit." />
<figcaption>Bunny rabits are cuddly and fluffy creatures with big ears. They eat carrots.</figcaption>
</figure>
If I don't use any CSS the figcaption will expand the width of the figure element beyond 200px. How can I prevent this?
I know I can force the text inside the figcaption to wrap by specifying the width of the figure element (<figure style="width:200px;">) but I don't really want to use this for each and every image.
Adding this Code to <figure> and <figcaption> CSS-Attributes helped me with the same problem. Also, it preserves the responsivenes of your images and captions.
figure { display: table; }
figcaption { display: table-caption; caption-side: bottom ; }
Adding display: table; sets the stage.
Adding display: table-caption; alone placed the caption on top of
the image, The caption-side property specifies the placement of
the table caption at the bottom, top is default.
This will place the figcaption side by side with the img:
figure {
display: table;
}
img, figcaption {
display: table-cell;
vertical-align: bottom;
}
figcaption {
padding-left: 4px;
}
Here's an example. However I'm not entirely clear what you're trying to achieve - you say in the question that you want the figure to stay at 200px width, but then you comment that you want the figcaption to appear to the right, which would make the figure wider. If all you want is for the figcaption to be restricted to the width of the image, this should work:
figure {
display: table;
width: 1px; /* This can be any width, so long as it's narrower than any image */
}
img, figcaption {
display: table-row;
}
Another solution: Use Intrinsic width
Just set width: min-content; on the figure element
DEMO (Except for IE)
figure {
width: -webkit-min-content;
width: -moz-min-content;
width: min-content;
}
<figure>
<img src=" http://placehold.it/200x150" width="200" height="150" alt="An image of a bunny rabbit." />
<figcaption>Bunny rabits are cuddly and fluffy creatures with big ears. They eat carrots.</figcaption>
</figure>
NB: Browser Support is OK, except for IE, however they are considering implementing this
Unfortunately, setting the width of the figure instead of using max-width: 100% means that it won't shrink on narrow (mobile) devices. That is, the images will not be responsive. I resorted to inserting <br /> to break up long captions, but I didn't like it. But this obscure CSS feature seems to work for me:
figcaption {
display: run-in;
width: 150px
}
This keeps the image responsive, even though the caption isn't. You can pick your own caption width. I also added margin: auto;
text-align: center; to center the caption on a mobile device.
This was really bothering me, because I wanted to find an answer to accommodate an upgrade to HTML5 that would successfully replace my original setup of displaying images and captions- a table with two rows (or one if no caption was available).
My solution might not work for everyone, but so far, it seems to do just fine in the major browsers (O, FF, IE, S, C), as well as being responsive on mobile devices:
figure {
border: 0px solid #000;
display: table;
width: 0;
}
The idea here is that figure is pushed into existence by the width of the img and so doesn't need any kind of direction.
figure img {
display: block;
}
This is used to rid ourselves of the useless, unsightly gap between the bottom of img and the bottom of figure.
figcaption {
text-align: left;
}
Now that figure has been pushed open just wide enough to let img in, figcaption text has only that limited amount of space in which to exist. text-align is not required for this solution to function.
This solution works as well as display: table-caption, but keeps figcaption contained in any border or background value that might need to be set.

CSS text replace with image, need hyperlink

I am using the text-indent technique to replace my <h1/> tag with my website's image as so:
<h1 title="Homepage">My logo</h1>
CSS:
#header h1 {
float: left;
background: transparent url('../images/logo.png');
width: 214px;
height: 64px;
text-indent: -9999px;
}
The only problem is that I want to still have the new image act as a hyperlink. I tried doing:
<h1 title="Homepage">My logo</h1>
But since it is being indented, the link is too. I wanted to know if anyone had any suggestions on how to do this and still be valid XHTML.
EDIT I'd rather do it in a way that is accessible to users with screen readers, from what I read, doing a display:none will not work with some readers.
There are many ways to do this, this is the way that I prefer, it works well, and is easy to implement.
<div id="header">
<h1>Homepage</h1>
</div>
Then i do this css, this is also know as the "Leafy/Langridge image replacement" method
#header h1 a {
display: block;
padding: 22px 0 0 0;
overflow: hidden;
background-image: url(../images/sidebar/heading.png);
background-repeat: no-repeat;
height: 0px !important;
height /**/:22px;
}
The only thing you should have to edit is the height, and the padding-top. In this example it is 22px, this should be equal to your image-height.
Why are you mucking about with negative indents - just use the alt attribute of the img tag?
<h1 title="Homepage><img src="images/logo.png" alt="My logo"/></h1>
#Partrik Hägne: You should't use display:none, because some screen readers will ignore that...
You can see a list of Nine Techniques for CSS Image Replacement on http://css-tricks.com, which describes the cons and pros for each solution.
What you can do is remove the indent. And use a span to hide instead:
<h1 title="Homepage"><span>My logo</span></h1>
#header h1 span
{
display: none;
}
You might have to set the width and height of the A-tag also since nothing fills using this trick.

Resources