A few other questions have already addressed how best to apply text-align: justify to get inline-block elements to spread out evenly… for example, How do I *really* justify a horizontal menu in HTML+CSS?
However, the 100% width element that "clears" the line of inline-block elements is given its own line by the browser. I can't figure out how to get rid of that empty vertical space without using line-height: 0; on the parent element.
For an example of the problem, see this fiddle
For my solution that uses line-height: 0;, see this fiddle
The solution I'm using requires that a new line-height be applied to the child elements, but any previously set line-height is lost. Is anyone aware of a better solution? I want to avoid tables so that the elements can wrap when necessary, and also flexbox because the browser support isn't there yet. I also want to avoid floats because the number of elements being spaced out will be arbitrary.
Updated the "Future" solution info below; still not yet fully supported.
Present Workaround (IE8+, FF, Chrome Tested)
See this fiddle.
Relevant CSS
.prevNext {
text-align: justify;
}
.prevNext a {
display: inline-block;
position: relative;
top: 1.2em; /* your line-height */
}
.prevNext:before{
content: '';
display: block;
width: 100%;
margin-bottom: -1.2em; /* your line-height */
}
.prevNext:after {
content: '';
display: inline-block;
width: 100%;
}
Explanation
The display: block on the :before element with the negative bottom margin pulls the lines of text up one line height which eliminates the extra line, but displaces the text. Then with the position: relative on the inline-block elements the displacement is counteracted, but without adding the additional line back.
Though css cannot directly access a line-height "unit" per se, the use of em in the margin-bottom and top settings easily accommodates any line-height given as one of the multiplier values. So 1.2, 120%, or 1.2em are all equal in calculation with respect to line-height, which makes the use of em a good choice here, as even if line-height: 1.2 is set, then 1.2em for margin-bottom and top will match. Good coding to normalize the look of a site means at some point line-height should be defined explicitly, so if any of the multiplier methods are used, then the equivalent em unit will give the same value as the line-height. And if line-height is set to a non-em length, such as px, that instead could be set.
Definitely having a variable or mixin using a css preprocessor such as LESS or SCSS could help keep these values matching the appropriate line-height, or javascript could be used to dynamically read such, but really, the line-height should be known in the context of where this is being used, and the appropriate settings here made.
UPDATE for minified text (no spaces) issue
Kubi's comment noted that a minification of the html that removes the spaces between the <a> elements causes the justification to fail. A pseudo-space within the <a> tag does not help (but that is expected, as the space is happening inside the inline-block element), a <wbr> added between the <a> tags does not help (probably because a break is not necessary to the next line), so if minification is desired, then the solution is a hard coded non-breaking space character --other space characters like thin space and en space did not work (surprisingly).
Nearing a Future Clean Solution
A solution in which webkit was behind the times (as of first writing this) was:
.prevNext {
text-align: justify;
-moz-text-align-last: justify;
-webkit-text-align-last: justify; /* not implemented yet, and will not be */
text-align-last: justify; /* IE */
}
It works in FF 12.0+ and IE8+ (buggy in IE7).
For Webkit, as of version 39 (at least, might have crept in earlier) it does support it without the -webkit- extension but only if the user has enabled the experimental features (which can be done at chrome://flags/#enable-experimental-web-platform-features). Rumor is that version 41 or 42 should see full support. Since it is not seamlessly supported by webkit yet, it is still only a partial solution. However, I thought I should post it as it can be useful for some.
Consider the following:
.prevNext {
display: table;
width: 100%
}
.prevNext a {
display: table-cell;
text-align: center
}
(Also see the edited fiddle.) Is that what you are looking for? The advantage of this technique is that you can add more items and they will all be centered automatically. Supported by all modern Web browsers.
First off, I like the approach of the pseudo-element in order to keep the markup semantic. I think you should stick with the overall approach. It's far better than resorting to tables, unnecessary markup, or over the top scripts to grab the positioning data.
For everyone stressed about text-align being hacky - c'mon! It's better that the html be semantic at the expense of the CSS than vice versa.
So, from my understanding, you're trying to achieve this justified inline-block effect without having to worry about resetting the line-height every time right? I contend that you simply add
.prevNext *{
line-height: 1.2; /* or normal */
}
Then you can go about coding as though nothing happened. Here's Paul Irish's quote about the * selector if you're worried about performance:
"...you are not allowed to care about the performance of * unless you concatenate all your javascript, have it at the bottom, minify your css and js, gzip all your assets, and losslessly compress all your images. If you aren't getting 90+ Page Speed scores, it's way too early to be thinking about selector optimization."
Hope this helps!
-J Cole Morrison
Attempting to text-align for this problem is pretty hackish. The text-align property is meant to align inline content of a block (specifically text) -- it is not meant to align html elements.
I understand that you are trying to avoid floats, but in my opinion floats are the best way to accomplish what you are trying to do.
In your example you have line-height:1.2, without a unit. This may cause issues. If you're not using borders you could give the parent and the children a line-height of 0.
The other options I can think of are:
Use display:table on the parent and display:table-cell on the children to simulate table like behaviour. And you align the first item left, and the last one right. See this fiddle.
Use javascript to do a count of the nav children and then give them a equally distributed width. eg. 4 children, 25% width each. And align the first and last items left and right respectively.
There is a way to evenly distribute the items but is a convoluted method that requires some non breaking spaces to be carefully placed in the html along with a negative margin and text-align:justify. You could try and adapt it the the nav element. See example here.
Your fiddle is awfully specific. It seems to me for your case this CSS would work well:
.prevNext {
border: 1px solid #ccc;
position: relative;
height: 1.5em;
}
.prevNext a {
display: block;
position: absolute;
top: 0;
}
.prevNext a:first-child {
left: 0;
text-align: left;
}
.prevNext a:last-child {
right: 0;
text-align: right;
}
As stated by #Scotts, the following has been implemented inside Chrome, without the -webkit part , which I really loved btw, specially since we need to get rid of the -browser-specific-shǐt real soon.
.prevNext {
text-align: justify;
-moz-text-align-last: justify;
-webkit-text-align-last: justify; /* not implemented yet, and will not be */
text-align-last: justify; /* IE + Chrome */
}
Note: Though still the Safari and Opera don't support it yet (08-SEPT-16).
I think the best way would be to create the clickable element with a specific class/id and then assign float:left or float:right accordingly. Hope that helps.
One of the more bewildering things about working with floats is how they can affect the element that contains them (their "parent" element). If this parent element contained nothing but floated elements, the height of it would literally collapse to nothing. This isn't always obvious if the parent doesn't contain any visually noticeable background, but it is important to be aware of.
I have background-image in parent element and 2 sub float elements. As above description says, its (parent element)height collapses to zero whenever it has only float elements. How can I fix it? I dont want to add height or any content to parent tag. I want height of parent element to auto-increase in accordance to content of floating elements? How can I achieve it?
you have different ways to manage floatting element and include them in the flow. Parents or aside elements needs their layout to be trigger in a way, it calculates room/space used by floatting elements.
here is a few ways that you can apply to your snippet :
/* different ways to play with layout */
.outerdiv:before { /* add classname in document to be abble to relat it to css rules applied , demo purpose */
content:attr(class);
position:absolute;
margin-top:-1.2em;
background:yellow;
}
.outerdiv { /* demo purpose , we stack them */
clear:both;
margin:1em auto;
}
/* here we go ========================================= */
.clearafter:after {
content:'';
display:block;
clear:both;
}
.displayib {display:inline-block;}
.displaytb {display:table;}
.overflowh {overflow:hidden;}
.overflowa {overflow:auto;}
.overflowv {overflow:visible;} /* defaut, doesn't trigger anything */
.float {float:left;}
http://jsfiddle.net/Xq2We/1/ you can see each possibilities and see what it involves as result.
To go further and understand better you can read this : http://css-tricks.com/all-about-floats/
add
#parent{
overflow:auto;
}
or clear floats using available techniques
I am trying to position a Twitter and Facebook image next to my portrait on my website but in order to get the positioning correct i have to use divs. The problem is that when i add a div to the image and a link to it the div makes the image unable to be clicked and go to the link. I can't get rid of the divs because its the only way for my images to be positioned correctly. I will post a JSfiddle below with the code.
JSFiddle: http://jsfiddle.net/HeyItsProdigy/RVUhV/
Area of issue : <div id="facebook"><img src="fb.png" height="101" width="101" />
The problem isn't exactly as you describe. The issue is that your positioning is causing your Twitter element to overlap the others, which makes them un-clickable.
There's unfortunately not an easy solution. I think you're going to have to rethink your whole CSS structure, including eliminating the deprecated <center> tags to figure this one out. Good luck.
Use z-index:
#twitter {
position:relative;
bottom:290px;
left:168px;
z-index: 1;
}
#facebook {
position:relative;
top:83px;
right:168px;
z-index: 5;
}
jsfiddle
However, this type of CSS styling shouldn't be used in this manner. Using rules such as top, left, bottom, right etc should rarely be used for positioning, unless using absolute positioned elements.
You should look into using margin and padding as well as display properties for positioning your divs. Much of this code can be taken out.
I'm very sorry to tell you, but the answer is: do a modern HTML tutorial!
You should try Code Academy they have interactive course for beginners and intermediates with direct feedback. It seems you got stuck with an old HTML 3/4 book which won't do you any good.
But I also got an direkt answer for your link problem: this fiddle where you include the images as background-images and by using your classes and selectors efficiently you have to write(mostly copy+paste) very few lines if you want to add something.
You do the most with this CSS part:
.socialmedia a {
display: block; /* Because the image is probably higher than the text */
height: 50px; /* you have to set it to block and height 50px to show the image */
padding-left: 55px; /* make room for the background image(50px) and extra margin(+5px) */
padding-top: 12px; /* center in the middle of the image */
padding-bottom: 12px;
text-decoration: none;
}
Example g+:
CSS:
.g a {
background: url(logo_g_50x50.png) no-repeat;
}
HTML
<li class="g">+1 me on g+</li>
and done!
It's easier to read and even easier to maintain for later reuse or additions
I'm trying to write css to style my columns automatically based on the elements on the page. There are several combinations of columns:
aside-article-aside
aside-article
article-aside
article
Each aside will have a class of either left or right, depending on which side of the screen it is on. The asides will always be a constant width no matter what the layout, but the article's width will change depending on the layout.
I want to use CSS (preferably without any javascript) to set the width of the article. I've been playing around with CSS siblings, but I can't quite get this to work. This is how I would theoretically like the code to work:
article{
/* just article */
width: some width;
}
.left~article{
/* aside-article */
width: some width;
}
.right~article{
/* article-aside */
width: some width; /* (this can be the same as the previous;
I don't know if it's easier to define
them together or separately) */
}
.left~.right~article{
/* aside-article-aside */
width: some-width;
}
The first two layouts work, bu the second two do not. The problem is that I always want to style the article, even if it is not the last in that section of the DOM. Using the selectors article~.right and .left~.article~.right for the last two layouts respectively finds the correct combination of layouts (i.e. either an article then an aside or an article between two asides) but then it targets the right-most aside and I can't change the style of the article.
Is there a way to take all siblings into account whether before the target element in the DOM using the sibling selectors in CSS? Or can anyone think of any "creative" ways I could get around this without having to use javascript?
Thanks!
CSS3 Solution
Assuming the containing element for these only has immediate children of either aside or article, then there is a CSS3 solution (so IE9+). For my example here, I am assuming an overall width of 400px and standard widths for aside elements (though that could be different).
aside {
width: 100px;
}
aside.left + article,
article:first-child {
width: 300px;
}
article:only-child {
width: 400px; /* overrides article:first-child if it is only-child */
}
aside.left:nth-last-of-type(2) + article {
width: 200px; /* only engages if there are two asides */
}
I have a span with several other spans inside it, and I want to toggle the sub-spans between display:block and display:inline. The spans start off with display:inline-block, then are switched to display:block. This works fine. The problem is when toggling back in Webkit (it works fine in Firefox): the spans are rendered with extra line breaks in between them.
Can I make this render correctly without putting <br/> tags between the spans?
demo here: http://jsbin.com/omalu3/4/edit
Any other solution would be a workaround since it's a browser bug.
An alternative to derekerdmann's solution:
#a.multiline * { width: 100% }
#a.oneline * { width: auto }
#a * { border:solid 1px black; display:inline-block }
Another workaround would be to not wrap the children spans with another span -- which is an inline element. Use a <div> for #a and it behaves correctly (in Webkit at least!).
On another note, the star selector is not really efficient, although I understand this is only an example so I'm not going to criticise that here :D
Now isn't that fun.
I'm not sure what's causing the problem, but it goes away if you add float: left; to #a.oneline *. When you do that, you could change the display to block so your styles look like this:
#a.multiline * { }
#a.oneline * { float:left; }
#a * { border:solid 1px black; display:block;}
The only difference between this solution and your original layout is that the oneline blocks will be aligned at the top instead of the bottom, but you could set a fixed height for those elements.