📜 ⬆️ ⬇️

Tableless justification or inline-blocks revisited

Everyone has long known about the cross-browser implementation of inline blocks, but not everyone knows that this implementation is not as cross-browser and complete as it seems. What, how and why we consider a simple example: let's make a menu whose items are evenly distributed across the entire width of the screen.

Usually in the menu markup it looks like this:
<ul class="menu"> <li class="menu-item"> <a href="/news"></a> </li> <li class="menu-item"> <a href="/swen"></a> </li> <li class="menu-item"> <a href="/profit"> </a> </li> </ul> 

And the css for this is approximately as follows:
 .menu-item { display: inline-block; } * html .menu-item { display: inline; zoom: 1; } *+html .menu-item { display: inline; zoom: 1; } 

The result is that each menu item is a word in a line (no matter how many words are inside the item, because the inline block is an indivisible unit with its own formatting context) and you need to do the following to stretch the words to the full width of the line:
 .menu { text-align: justify; } .menu-item { display: inline-block; text-align: left; } * html .menu-item { display: inline; zoom: 1; } *+html .menu-item { display: inline; zoom: 1; } 

But it will not give the desired result, because in css there is no full-justify value for the text-align property, and the usual justify stretches the spacing between words in the lines except the last one, so we need to write some long enough word that would be transferred to the new line (in css3 there is a text- Align-last to manipulate the alignment of the last line, but it will roll only in the bright future). Of course, writing a word is not a very good option; you just need to make another menu item and stretch it 100% of the parent's width (less than 100 is possible, then you can achieve a rather interesting effect):

 <ul class="menu"> <li class="menu-item"> <a href="/news"></a> </li> <li class="menu-item"> <a href="/swen"></a> </li> <li class="menu-item"> <a href="/profit"> </a> </li> <li class="menu-item menu-item_sizer"> &nbsp; </li> </ul> 

 .menu { text-align: justify; } .menu-item { display: inline-block; text-align: left; } * html .menu-item { display: inline; zoom: 1; } *+html .menu-item { display: inline; zoom: 1; } .menu-item_sizer { width: 100%; } 

This code will work equally well in all browsers ... except Internet Explorer 6 and 7 (who would doubt). And the problem lies in the fact that such "inline-blocks" in these versions of the explorer are "too block" - they do not take into account the whitespace characters around them. Illustrative example:
 <span class="inlineBlock">Test</span> word 

In normal browsers, it will look like this:
 Test word 

In older versions of the explorer:
 Testword 

Fortunately, there is a solution to this problem and it lies on the surface - it is necessary to make this “inline block” more inline, for this it needs to be wrapped in an inline element. What happens:
 <ul class="menu"> <li class="menu-item_wrap"> <div class="menu-item"> <a href="/news"></a> </div> </li> <li class="menu-item_wrap"> <div class="menu-item"> <a href="/swen"></a> </div> </li> <li class="menu-item_wrap"> <div class="menu-item"> <a href="/profit"> </a> </div> </li> <li class="menu-item_wrap menu-item_sizer"> &nbsp; </li> </ul> 

 .menu { text-align: justify; } .menu-item_wrap { display: inline; } .menu-item { display: inline-block; text-align: left; } * html .menu-item { display: inline; zoom: 1; } *+html .menu-item { display: inline; zoom: 1; } .menu-item_sizer { width: 100%; } 

But this will not give the desired result, although everything seems to be as it should. The problem is that the explorer does not consider each item as a single whole, and therefore everything falls apart - it's in the whitespace of the closing sequence of tags. Fixed simply:
 <ul class="menu"> <li class="menu-item_wrap"> <div class="menu-item"> <a href="/news"></a></div></li> <li class="menu-item_wrap"> <div class="menu-item"> <a href="/swen"></a></div></li> <li class="menu-item_wrap"> <div class="menu-item"> <a href="/profit"> </a></div></li> <li class="menu-item_wrap menu-item_sizer">&nbsp;</li> </ul> 

If you use a template engine, then let it do the work (for example, the spaceless tag in the django templates or jinja).
Now everything looks good and since it is necessary in all browsers ... as long as we do not want to do something interesting inside each item, let it be the icon pressed to the right edge of each item:
 <ul class="menu"> <li class="menu-item_wrap"> <div class="menu-item"> <span class="menu-item-icon"> </span> <a href="/news"></a></div></li> <li class="menu-item_wrap"> <div class="menu-item"> <span class="menu-item-icon"> </span> <a href="/swen"></a></div></li> <li class="menu-item_wrap"> <div class="menu-item"> <span class="menu-item-icon"> </span> <a href="/profit"> </a></div></li> <li class="menu-item_wrap menu-item_sizer">&nbsp;</li> </ul> 

 .menu { text-align: justify; } .menu-item_wrap { display: inline; } .menu-item { background-color: Green; display: inline-block; padding: 5px 15px; position: relative; text-align: left; } * html .menu-item { display: inline; zoom: 1; } *+html .menu-item { display: inline; zoom: 1; } .menu-item_sizer { width: 100%; } .menu-item-icon { background-color: Red; height: 5px; position: absolute; right: 0; } 

In all browsers, including old explorators, everything is OK ... except for all versions of Opera (who would doubt). In Opera, you can see that the icon is not pressed to the right edge of the item, but to the left is a banal bug that will prevent developers from living for another 10 years, no less. It lies in the fact that if there is no block element or text in the inline-block element, the positioning limits are violated. This is fixed by adding another, inner, block wrapper.
 <ul class="menu"> <li class="menu-item_outerWrap"> <div class="menu-item"> <div class="menu-item_innerWrap"> <span class="menu-item-icon">&nbsp;</span> <a href="/news"></a></div></div></li> <li class="menu-item_outerWrap"> <div class="menu-item"> <div class="menu-item_innerWrap"> <span class="menu-item-icon">&nbsp;</span> <a href="/swen"></a></div></div></li> <li class="menu-item_outerWrap"> <div class="menu-item"> <div class="menu-item_innerWrap"> <span class="menu-item-icon">&nbsp;</span> <a href="/profit"> </a></div></div></li> <li class="menu-item_outerWrap menu-item_sizer">&nbsp;</li> </ul> 

 .menu { text-align: justify; } .menu-item_outerWrap { display: inline; } .menu-item { background-color: Green; display: inline-block; padding: 5px 15px; position: relative; text-align: left; } * html .menu-item { display: inline; zoom: 1; } *+html .menu-item { display: inline; zoom: 1; } .menu-item_innerWrap { display: block; } .menu-item_sizer { width: 100%; } .menu-item-icon { background-color: Red; height: 5px; position: absolute; right: 0; } 

Now the main thing is not to include some block element inside .menu-item hasLayout in IE6, since This will trigger the widening of our inline block. This can be solved by setting a fixed width for the block element (if you need a width for the content, you need to specify a zero width, but only for IE6).

On the one hand, it was not easy and not quite beautiful, but on the other hand, we got a solution that behaves as it should and can be used safely (almost) in other places, for example, to create our own controls that would behave in content like standard browser controls (to change the behavior of such a control, you need to apply everything to the inline-block part of it, for example, if you want to make the element block or floating).
')
Well, for a pinning effect, the “formula” of this inline block in zen-css-like pseudo-code is:
 inline>inline-block>block 


Can someone still tell the administration that we need to highlight CSS? And then my request was somehow ignored.

Source: https://habr.com/ru/post/81611/


All Articles