I am faceing very strange behaviour of flexbox for my page layout.I am using FontAwesome to render certain symbols.
Basically, I have 2 flexbox items inside another flexbox item, and these child items render wider than parent item.
1) I have a .content__header
object, which is rendered as a flexbox object inside another series of flexbox objects.
2)The .content__header
object contains 2 child objects: .breadcrumb
and .page_tools
. These child objects are rendered as flex items as well.
3) Inside the .breadcrumb
object, I have some span
objects (.breadcrumb__test
) who's content is replaced by a FontAwesome icon. The replacement is done using absolute positioning of the ::after
pseudo-element.
4) When I remove all .breadcrumb__text
HTML elements or just remove the .breadcrumb__text::after
definition from my stylesheet - which defines the use of the FontAwesome font - the child objects (.breadcrumb
and .page_tools
) render at their correct width. So I guess it has something to do with the replacement by a FontAwesome icon.
.breadcrumb__text::after {
font-family: "FontAwesome";
font-weight: 400;
}
The green line indicates the difference between the parent width and it's actual contents.
Code & Fiddle below.
Browser: Google Chrome 47.0.2526.106 m
https://jsfiddle.net/44gymmw2/6/
When I remove text-indent: 100%;
from the .breadcrumb__text
CSS definition, the .breadcrumb
renders as intended. However, when I leave the text-indent
in place, and remove the .breadcrumb__text::after
definition at the top of the style sheet (as described above), it also renders correctly.
Might this issue have something to do with the either FontAwesome or text-indent
and flexbox?
HTML
<body>
<div class="layout_wrapper">
<div class="layout_container__content">
<div class="content">
<header class="content__header">
<div class="breadcrumb">
<span class="breadcrumb__text breadcrumb__text--first">From </span><a class="breadcrumb__link" href="#">Dashboard</a><span class="breadcrumb__text"> to </span><a class="breadcrumb__link" href="#">Find records</a><span class="breadcrumb__text"> to </span>
<h1 class="breadcrumb__current">Kylo Ren’s Command Shuttle™</h1>
</div>
<ul class="page_tools">
<li class="page_tools__item">
<button type="button" class="button button--primary">Save</button>
</li>
<li class="page_tools__item">
<button type="button" class="button">Cancel</button>
</li>
</ul>
</header>
</div>
</div>
<div class="layout_container__sidebar">
<div class="sidebar">
<article class="widget">
<h2 class="widget__title">Widget</h2>
</article>
</div>
</div>
</div>
</body>
CSS
/* Removing this makes it work */
.breadcrumb__text::after {
font-family: "FontAwesome";
font-weight: 400;
}
/* Don't remove anything below */
.breadcrumb__text--first {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
* {
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
html, body {
padding: 0;
margin: 0;
}
body {
display: flex;
flex-flow: column nowrap;
align-items: stretch;
}
.layout_wrapper {
flex: 1 1 auto;
display: flex;
flex-flow: row nowrap;
align-items: stretch;
}
.layout_container__content {
flex: 0 0 75vw;
}
.layout_container__sidebar {
flex: 0 0 25vw;
}
.content {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-items: stretch;
}
.content__header {
outline: 1px solid blue;
background-color: #434649;
color: #ffffff;
flex: 0 0 100%;
display: flex;
flex-flow: row nowrap;
}
.breadcrumb {
outline: 3px dashed purple;
flex: 1 1 auto;
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
.breadcrumb__text {
flex: 0 0 2em;
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
position: relative;
text-align: center;
}
.breadcrumb__text::after {
content: '\f105';
padding: 0;
text-indent: 0;
position: absolute;
top: 0;
right: 0;
width: 100%;
}
.breadcrumb__text--first {
flex: 0 0 0;
}
.breadcrumb__text--first::after {
content: none;
}
.breadcrumb__link {
flex: 0 0 auto;
display: inline-block;
font-size: 0.8571rem;
}
.breadcrumb__current {
flex: 0 0 100%;
margin: 0;
}
.page_tools {
outline: 3px dashed red;
flex: 0 0 auto;
display: flex;
flex-flow: row nowrap;
list-style: none outside none;
}
The main size of a flex item is the size it has in the main dimension. If you are working in a row — in English — then the main size is the width. In a column in English, the main size is the height. Items also have a minimum and maximum main size as defined by their min-width or min-height on the main dimension.
Flexbox is a relatively new front-end feature that makes building a website layout (and making it responsive!) much, much easier than it used to be. In days past, to build a website, you would have to use float grids or even tables to make your layout look like it should.
Flexbox is a layout model that allows elements to align and distribute space within a container. Using flexible widths and heights, elements can be aligned to fill a space or distribute space between elements, which makes it a great tool to use for responsive design systems.
I just finished reviewing your code and noticed the following:
display: flex;
).flex-flow: row no-wrap;
and align-items: stretch
).That said, lets continue to your issue. It isn't obvious, so it needs some introduction.
Pangloss introduces an important ingredient of your issue, which affects using text-indent
. From W3:
The box is indented with respect to the left (or right, for right-to-left layout) edge of the line box. User agents must render this indentation as blank space.
[...]
If the value of
text-indent
is either negative or exceeds the width of the block, that first box, described above, can overflow the block. The value ofoverflow
will affect whether such text that overflows the block is visible.
In other words: text-indent
affects the dimensions of the box you apply it to.
You have declared overflow: hidden;
on .breadcrumb__text
. Obviously, for that declaration to have the desired effect, the box you applied it to needs a width
, or else it wouldn't have a clipping edge.
.breadcrumb__text
should get its width from the flex-basis
declaration (specifically flex: 0 0 2em;
) applied to it. Well... that's not happening, at least, not entirely as you would expect. Even though its width seems to be 2em
, for some reason it doesn't trigger the overflow behavior as it should. This seems to be a bug in the specific Chrome version you use, as its fixed in Canary (eg. version 49 and up).
So: this seems to be an issue with the flexbox implementation in Chrome. That said, with this knowledge, your issue can be fixed in multiple ways. Some examples:
text-indent: -100%
Using text-indent: -100%
fixes your issue because it takes away the extra whitespace on the right side of the affected elements. (→ jsfiddle)
width: 2em
You could add the declaration width: 2em
to .breadcrumb__text
. That would fix the unexpected behavior of the flex-basis
declaration. (→ jsfiddle)
overflow: hidden;
on parent containerAdding overflow: hidden;
on .breadcrumbs
fixes your issue. Now the parent container has a clipping edge and handles the whitespace caused by using text-indent: 100%
. (→ jsfiddle)
Flexbox is a powerful layout mode and it sure is great to experiment with. But, the algorithms are complex and browser implementations aren't free from issues yet. Make sure you take this into account when using flexbox.
Another concern when looking at your code is the way you use flexbox. Flexbox is there for you to use, but it doesn't necessarily have to replace every other way of dealing with layout. display: inline-block;
or display: table;
, or even float
might do the job without introducing the complexity of nested flex containers.
The FontAwesome typeface isn't the root cause. It's the H1 "block" layout definition set by default in your browser. Add this style to your breadcrumb__current class. See https://jsfiddle.net/44gymmw2/9/
word-wrap:break-word
The H1 tag is a block level element, which will make it push the contents of that block across the entire page. One other fix would be to change that from block to inline, like so:
h1 { display: inline; }
Or you could wrap that text in another element, like a span.
I think the problem is caused by the text-indent:100%
rule, that added extra space on the right hand.
The
text-indent
property specifies how much horizontal space should be left before the beginning of the first line of the text content of an element.<percentage>
value relative to the containing block width. -MDN
See this simple demo:
body {
width: 200px;
border: 1px solid red;
}
span {
text-indent: 100%;
display: inline-block;
}
<span>text</span>
In your example, you can just change text-indent:100%
to text-indent:-9999px
, it works similarly, and it won't create the overflow.
Updated jsfiddle
Try witn inline-block property it is working good.
.content {
display:inline-block;
flex-flow: row wrap;
justify-content: space-between;
align-items: stretch;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With