Bài viết này thực hiện (hoặc lụm bài về đăng câu like từ các trang khác) bởi Việt Lâm Coder một YOUTUBER có tâm và đẹp trai siêu cấp vô địch zũ trụ. Các bạn đi ngang nếu được cho Lâm 1 like và 1 đăng ký kênh Youtube nhé !!
While iterating on a new article layout for the impending Cloud Four redesign, I encountered an old CSS layout problem.
For long-form content, it’s usually a good idea to limit line lengths for readability. The most straightforward way to do that is to wrap the post content in a containing element:
1 2 3 4 5 6 |
<span class="token selector">.u-containProse</span> <span class="token punctuation">{</span> <span class="token property">max-width</span><span class="token punctuation">:</span> 40em<span class="token punctuation">;</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
1 2 3 4 5 |
<span class="token tag"><span class="token punctuation"><</span>div <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>u-containProse<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span>...<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span>...<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"></</span>div<span class="token punctuation">></span></span> |
But what if we want some content to extend beyond the boundaries of our container? Certain images might have greater impact if they fill the viewport:
In the past, I’ve solved this problem by wrapping everything but full-width imagery:
1 2 3 4 5 6 7 8 |
<span class="token tag"><span class="token punctuation"><</span>div <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>u-containProse<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span>...<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"></</span>div<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>img <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>...<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>...<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>div <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>u-containProse<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span>...<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"></</span>div<span class="token punctuation">></span></span> |
But adding those containers to every post gets tedious very quickly. It can also be difficult to enforce within a content management system.
I’ve also tried capping the width of specific descendent elements (paragraphs, lists, etc.):
1 2 3 4 5 6 7 8 9 |
.u-containProse p, .u-containProse ul, .u-containProse ol, .u-containProse blockquote<span class="token comment" spellcheck="true">/*, etc. */</span> <span class="token punctuation">{</span> <span class="token property">max-width</span><span class="token punctuation">:</span> 40em<span class="token punctuation">;</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Aside from that selector giving me nightmares, this technique might also cause width
, margin
or even float
overrides to behave unexpectedly within article content. Plus, it won’t solve the problem at all if your content management system likes to wrap lone images in paragraphs.
The problem with both solutions is that they complicate the most common elements (paragraphs and other flow content) instead of the outliers (full-width imagery). I wondered if we could change that.
Flipping the Script
To release our child element from its container, we need to know how much space there is between the container edge and the viewport edge… half the viewport width, minus half the container width. We can determine this value using the calc()
function, viewport units and good ol’ percentages (for the container width):
1 2 3 4 5 |
<span class="token selector">.u-release</span> <span class="token punctuation">{</span> <span class="token property">margin-left</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>-50vw + 50%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>-50vw + 50%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Voilà! Any element with this class applied will meet the viewport edge, regardless of container size. Here it is in action:
Browsers like Opera Mini that don’t support calc()
or viewport units will simply ignore them.
One Big, Dumb Caveat
When I found this solution, I was thrilled. It seemed so clever, straightforward, predictable and concise compared to my previous attempts. It was in the throes of patting myself on the back that I first saw it…
An unexpected scrollbar:
On any page with this utility class in use, a visible vertical scrollbar would always be accompanied by an obnoxious horizontal scrollbar. Shorter pages didn’t suffer from this problem, and browsers without visible scrollbars (iOS Safari, Android Chrome) seemed immune as well. Why??
I found my answer buried deep in the spec (emphasis mine):
The viewport-percentage lengths are relative to the size of the initial containing block. When the height or width of the initial containing block is changed, they are scaled accordingly. However, when the value of overflow on the root element is auto, any scroll bars are assumed not to exist. Note that the initial containing block’s size is affected by the presence of scrollbars on the viewport.
Translation: Viewport units don’t take scrollbar dimensions into account unless you explicitly set overflow
values to scroll
. But even that doesn’t work in Chrome or Safari (open bugs here and here).
I reacted to this information with characteristic poise:
Luckily, a “fix” was relatively straightforward:
1 2 3 4 5 |
<span class="token selector">html, body</span> <span class="token punctuation">{</span> <span class="token property">overflow-x</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
It’s just a shame that it’s even necessary.
Bài viết này thực hiện (hoặc lụm bài về đăng câu like từ các trang khác) bởi Việt Lâm Coder một YOUTUBER có tâm và đẹp trai siêu cấp vô địch zũ trụ. Các bạn đi ngang nếu được cho Lâm 1 like và 1 đăng ký kênh Youtube nhé !!