📜 ⬆️ ⬇️

Change the width of the element with a "step" of several pixels

I would like to make a reservation in advance that unfortunately, pure CSS won't work out here: Firefox and IE8 + are too accurate (yes, in this case it is bad) they calculate the width of the blocks. However, for these browsers, a simple script is added in a couple of lines, if you still need to achieve the ideal, even though it spoils the charm.

For those who are too lazy to read everything, a link to the final version: jsfiddle.net/XeFTr/11

What is the point?


The bottom line is that sometimes it is necessary to display a rubber block with several children on the page, and the offspring must either be completely visible or not visible at all. The simplest example is a ribbon of some pictures with scrolling and arrows on the sides. It looks ugly looking out from under the "overflow: hidden" image, cropped on the side. The output is to force the width of the wrapper to always be a multiple of some pixels.
Of course, if the width of the descendants varies from element to element, then this method does not make sense.
')

How it works?


The principle of operation is that most browsers calculate the width of the child, if it is given as a percentage, based on the width of the parent. Thus, if an element has a width of 1000%, then when the width of its parent is changed by a pixel, the element itself will stretch or shrink by 10 pixels. Actually, everything.

Sergei Chikuyonok described this piece in a Lebedev screencast as early as 2008, in the context of fixing a bug with “jumping” blocks in IE6. However, to my surprise, I did not find a description of this most amusing technology on Habré.

How to write it?


I will consider a spherical element in vacuum, initially consisting solely of a block with “overflow: hidden” and a very wide element with a handful of descendants, the total width of which will exceed the width of the wrapper:

<div class="wrapper"> <ul class="itemList"> <li class="item"></li> <li class="item"></li> <li class="item"></li> <li class="item"></li> <li class="item"></li> <li class="item"></li> </ul> </div> 

 .wrapper { border: 1px solid black; margin: 10px; overflow: hidden; width: 60%; /*        */ } .itemList { height: 90px; list-style: none; margin: 0; padding: 0; width: 10000%; /*        */ } .item { background: green; /*   ,    */ display: inline; /*  ,    IE6 */ float: left; height: 80px; margin: 5px; padding: 0; width: 140px; } 

Living example: jsfiddle.net/KKSCe/4

So, we have a list of elements, the width of each (including the margin) is 150px. Obviously, the last element of the list will be seen entirely in one case out of 150. Well, in 11 cases: you can leave the five-pixel right margin out of sight and accept that the left margin is part of the previous element. :-)

It is clear from the description above that you need to add a wrapper to the “.wrapper” block, and set the “.wrapper” to a width 150 times larger than the width of this wrapper. It is also clear that if you write “width: 15000%” without additional manipulations, the result will be somewhat different from what is required. It is necessary that the ".wrapper" has a width of 60% of the screen width. This is compensated by the small width of the wrapper, calculated by proportion.
15000/100 = 60 / x
x = 0.4
We write this:

 <div class="pre-wrapper"> <div class="wrapper">......</div> </div> 

 .pre-wrapper { margin: 10px; width: 0.4%; } .wrapper { border: 1px solid black; overflow: hidden; width: 15000%; } 

A live example (look in Chrome or something): jsfiddle.net/XeFTr/9
You can expand the viewing area there and see how cool everything works. The block does accept widths that are multiples of 150px.
It would seem great!

But all is not so smooth


The problem is that in some cases, as in this example, you have to set the width of the wrapper to less than one percent - when the step should be more than 100px. Most browsers swallow it and consider it right. Even IE6. But with the Opera, including the latest versions - the trouble. Opera does not understand the meaning of less than 1%.

The solution is quite simple, but requires more HTML. Instead of doing one block with a width of 0.4%, we’ll do two. The width of the first is 1%, the width of the second, enclosed in the first, is 40%. Here and Opera becomes a series of consonants.

 <div class="pre-wrapper"> <div class="opera-fix"> <div class="wrapper">......</div> </div> </div> 

 .pre-wrapper { margin: 10px; width: 1%; } .opera-fix { width: 40%; } 

Live example: jsfiddle.net/XeFTr/8

It is possible that the use of values ​​less than 1% in sideways and in other browsers, but I have not seen this. Correct me if I am wrong.
However, in any case, a fractional percentage is not particularly good.

So, now everything works everywhere except for Firefox and IE of the latest versions. Correct this.

Script for overly accurate browsers


For simplicity, I will use jQuery. Function, like markup, is also for lab conditions.
 $(function() { if ( $.browser.mozilla || ($.browser.msie && $.browser.version >= 8) ) { resizeFix(); $(window).resize(resizeFix); } }); function resizeFix() { var w, h = $('.wrapper'), i = $('.item').outerWidth() + parseInt($('.item').css('marginLeft')) * 2; h.width(''); w = Math.floor(h.width() / i) * i; h.width(w + 'px'); } 

The final version: jsfiddle.net/XeFTr/11

I summarize


In more close to life examples there are all sorts of arrows, frames and the like. Their positioning (in particular, the positioning of elements on the side where the block is stretched) is done in exactly the same way.

Checked performance in Firefox, Opera, Chrome, IE6-9 and Safari under Windows.
It would be great to look at all this under a variety of Safari under MacOS, Konqueror, etc.
Also I will be glad to comments / corrections.

The basis of the written is the screencast mentioned above and subsequent independent research and experiments on this topic.

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


All Articles