Я столкнулся с очень странным поведением flexbox для макета моей страницы. Я использую Font Awesome для визуализации определенных символов.

По сути, у меня есть 2 элемента Flexbox внутри другого элемента Flexbox, и эти дочерние элементы визуализируются шире, чем родительский элемент.

1) У меня есть объект .content__header, который отображается как объект flexbox внутри другой серии объектов flexbox.

2) Объект .content__header содержит 2 дочерних объекта: .breadcrumb и .page_tools. Эти дочерние объекты также отображаются как гибкие элементы.

3) Внутри объекта .breadcrumb у меня есть несколько объектов span (.breadcrumb__test), содержимое которых заменено на FontAwesome. Замена выполняется с использованием абсолютного позиционирования псевдоэлемента ::after.

4) Когда я удаляю все элементы HTML .breadcrumb__text или просто удаляю определение .breadcrumb__text::after из своей таблицы стилей, которое определяет использование шрифта FontAwesome, дочерние объекты (.breadcrumb и { {X3}}) отображаются с правильной шириной. Я предполагаю, что это как-то связано с заменой значком FontAwesome.

.breadcrumb__text::after {
  font-family: "FontAwesome";
  font-weight: 400;
}

Визуальное представление проблемы

Зеленая линия указывает разницу между шириной родительского элемента и его фактическим содержимым.

Visual representation of the issue

Код и скрипт ниже.

Браузер: Google Chrome 47.0.2526.106 m


Скрипки :

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


Обновить

Когда я удаляю text-indent: 100%; из определения CSS .breadcrumb__text, .breadcrumb отображается как задумано. Однако, когда я оставляю text-indent на месте и удаляю определение .breadcrumb__text::after в верхней части таблицы стилей (как описано выше), оно также отображается правильно.

Может ли эта проблема иметь какое-то отношение к FontAwesome или text-indent и 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;
}
20
Gerrit Bertier 23 Дек 2015 в 14:21

4 ответа

Лучший ответ

Я только что закончил просматривать ваш код и заметил следующее:

  • Есть ненужные (вложенные) гибкие контейнеры (вызванные использованием display: flex;).
  • Есть ненужные объявления, связанные с гибкостью (просто декларация поведения по умолчанию, например flex-flow: row no-wrap; и align-items: stretch).
  • Есть несколько ненужных объявлений в контексте различных не связанных селекторов. Вероятно, оставшиеся объявления при тестировании / отладке.

Тем не менее, давайте продолжим вашу проблему. Это неочевидно, поэтому нужно немного представить.

Pangloss описывает важный компонент вашей проблемы, который влияет на использование text-indent. Из W3:

Поле имеет отступ относительно левого (или правого, для компоновки справа налево) края линейного поля. Пользовательские агенты должны отображать этот отступ как пустое пространство.

[...]

Если значение text-indent либо отрицательно, либо превышает ширину блока, это первое поле, описанное выше, может переполнять блок. Значение overflow повлияет на то, будет ли виден такой текст, который выходит за пределы блока.

Другими словами: text-indent влияет на размеры блока, к которому вы его применяете.

Вы заявили overflow: hidden; на .breadcrumb__text. Очевидно, что для того, чтобы это объявление имело желаемый эффект, блок, к которому вы его применили, должен иметь width, иначе у него не было бы обрезающего края.

.breadcrumb__text должен получить свою ширину из объявления flex-basis (в частности, flex: 0 0 2em;), примененного к нему. Ну ... этого не происходит, по крайней мере, не полностью , как вы ожидали. Хотя его ширина кажется равной 2em, по какой-то причине он не запускает поведение переполнения, как должно. Похоже, это ошибка конкретной версии Chrome, которую вы используете, поскольку она исправлена ​​в Canary (например, версия 49 и выше).

Итак: похоже, это проблема с реализацией flexbox в Chrome. Тем не менее, обладая этим знанием, вашу проблему можно решить несколькими способами. Некоторые примеры:

text-indent: -100%

Использование text-indent: -100% устраняет вашу проблему, поскольку убирает лишние пробелы с правой стороны затронутых элементов. (→ jsfiddle)

width: 2em

Вы можете добавить объявление width: 2em в .breadcrumb__text. Это исправит неожиданное поведение объявления flex-basis. (→ jsfiddle)

overflow: hidden; в родительском контейнере

Добавление overflow: hidden; на .breadcrumbs решает вашу проблему. Теперь родительский контейнер имеет обрезной край и обрабатывает пробелы, вызванные использованием text-indent: 100%. (→ jsfiddle)

Заключительные замечания

Flexbox - это мощный режим макета, с которым приятно экспериментировать. Но алгоритмы сложны, и реализации в браузерах пока не свободны от проблем. Убедитесь, что вы приняли это во внимание при использовании flexbox.

Еще одна проблема при просмотре кода - это способ использования flexbox. Flexbox существует для вас, но он не обязательно должен заменять любой другой способ работы с макетом. display: inline-block; или display: table;, или даже float могут сделать эту работу, не внося сложности вложенных гибких контейнеров.

8
Community 20 Июн 2020 в 09:12

Попробуйте использовать свойство inline-block, оно работает хорошо.

.content {
  display:inline-block;
  flex-flow: row wrap;
  justify-content: space-between;
  align-items: stretch;
}
1
riazshah 30 Дек 2015 в 10:25

Шрифт FontAwesome не является основной причиной. Это определение макета блока H1, установленное по умолчанию в вашем браузере. Добавьте этот стиль в свой класс breadcrumb__current. См. https://jsfiddle.net/44gymmw2/9/.

 word-wrap:break-word 

Тег H1 - это элемент уровня блока, который заставляет его перемещать содержимое этого блока по всей странице. Еще одно исправление - изменить это с блока на встроенный, например:

h1 { display: inline; }

Или вы можете обернуть этот текст другим элементом, например диапазоном.

3
Ken Palmer 23 Дек 2015 в 14:37

Я думаю, что проблема вызвана правилом text-indent:100%, которое добавило дополнительное пространство справа.

Свойство text-indent указывает, сколько горизонтального пространства должно быть быть оставленным перед началом первой строки текстового содержания элемент. Значение <percentage> относительно содержащего блока ширина . - MDN

Посмотрите эту простую демонстрацию:

body {
  width: 200px;
  border: 1px solid red;
}
span {
  text-indent: 100%;
  display: inline-block;
}
<span>text</span>

В вашем примере вы можете просто изменить text-indent:100% на text-indent:-9999px, он работает аналогичным образом и не создает переполнения.

Обновленный jsfiddle

1
Stickers 27 Дек 2015 в 21:59