Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flexbox sizing doesn't work correctly when using FontAwesome

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;
}

Visual representation of the issue

The green line indicates the difference between the parent width and it's actual contents.

Visual representation of the issue

Code & Fiddle below.

Browser: Google Chrome 47.0.2526.106 m


Fiddle:

https://jsfiddle.net/44gymmw2/6/


Update

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?


Code

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;
}
like image 268
Gerrit Bertier Avatar asked Dec 23 '15 11:12

Gerrit Bertier


People also ask

How does Flexbox define size?

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.

Is Flexbox responsive?

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.

When should I use Flexbox layout?

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.


4 Answers

I just finished reviewing your code and noticed the following:

  • There are unnecessary (nested) flex containers (caused by using display: flex;).
  • There are unnecessary flex-related declarations (just declaring the default behavior, such as flex-flow: row no-wrap; and align-items: stretch).
  • There are several unnecessary declarations in the context of various unrelated selectors. Probably left-over declarations while testing / debugging.

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 of overflow 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 container

Adding 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)

Final remarks

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.

like image 117
pesla Avatar answered Oct 09 '22 02:10

pesla


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.

like image 31
Ken Palmer Avatar answered Oct 09 '22 02:10

Ken Palmer


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

like image 1
Stickers Avatar answered Oct 09 '22 04:10

Stickers


Try witn inline-block property it is working good.

.content {
  display:inline-block;
  flex-flow: row wrap;
  justify-content: space-between;
  align-items: stretch;
}
like image 1
riazshah Avatar answered Oct 09 '22 03:10

riazshah