Почему псевдо-элементы: before и: after требуют свойства "content"?

учитывая следующий сценарий, почему селектор: after требует, чтобы свойство содержимого функционировало?

.test {
    width: 20px;
    height: 20px;
    background: blue;
    position:relative;
}
			
.test:after {
    width: 20px;
    height: 20px;
    background: red;
    display: block;
    position: absolute;
    top: 0px;
    left: 20px;
}
<div class="test"></div>

обратите внимание, как вы не видите псевдоэлемент, пока не укажете свойство content:

.test {
    width: 20px;
    height: 20px;
    background: blue;
    position:relative;
}
			
.test:after {
    width: 20px;
    height: 20px;
    background: red;
    display: block;
    position: absolute;
    top: 0px;
    left: 20px;
    content:"hi";
}
<div class="test"></div>

Почему это нервирует? Вы могли бы подумать, что блок отображения заставит элемент отображаться. Как ни странно, вы действительно можете видеть стили внутри web отладчики; однако, они не отображаются на странице.

4 ответов


вот некоторые ссылки на различные спецификации и проекты W3C:

Селекторы Уровня 3

псевдо-элементы": before "и": after " могут использоваться для вставки сгенерированного содержимого до или после содержимого элемента.

на :before и :after псевдо-элементы

авторы определяют стиль и расположение контента с помощью :before и :after псевдо-элементы. Как их имена указывают, что псевдо-элементы: before и: after указывают местоположение содержимого до и после содержимого дерева документов элемента. свойство "content" в сочетании с этими псевдоэлементами указывает, что вставляется.

атрибут content

исходные: нет

это свойство используется с псевдо-элементами: before и: after для создание содержимого в документе. Значения имеют следующие значения:

нет - псевдо-элемент не создается.


стиль, применяемый к ::before и:: after псевдо-элементам, влияет на отображение сгенерированного содержимого. The content атрибут is этот сгенерированный контент, и без него присутствует, значение по умолчанию content: none предполагается, что нет ничего для стиля, который будет применяться к.

если вы не хотите повторить content:''; несколько раз вы можете переопределить это просто путем глобального стиля all :: before и:: after псевдо-элементов в вашем CSS (пример JSFiddle):

::before, ::after {
    content:'';
}

основываясь на ваших комментариях к ответам других, я считаю, что ваш вопрос на самом деле:

почему свойство content для псевдоклассов должно быть установлено в CSS, как в отличие от содержимого не-псевдо-классов, которое может быть установлено в HTML или CSS?

причина в том, что:

  • по определению псевдоклассы динамически создаются для каждого отдельного элемента, заданного разметкой HTML страницы
  • все элементы страницы, включая псевдоклассы, должны иметь свойство содержимого для отображения.
  • HTML элементы, такие как <p> сделайте также, но вы можете быстро установить их свойство контента, используя разметку (или с объявлениями CSS).
  • однако, в отличие от не-псевдо-class-elements, псевдо-классы не может задаются значения в самой разметке.
    поэтому все псевдоклассы невидимый (их свойства "содержание" не имеют значения)если вы не скажете им не быть (давая им значение с объявлениями CSS).

возьмите эту простую страницу:

<body>
<p> </p>
</body>

мы знаем, что эта страница ничего не отобразит, потому что <p> элемент не содержит текста. Более точный способ перефразировать это, это на <p> свойство содержимого элемента не имеет значения.

мы можем легко изменить это, задав свойство content элемента h1 в разметке HTML:

<body>
<p>This sentence is the content of the p element.</p>
</body>

теперь это будет отображаться при загрузке, потому что свойство содержимого <p> элемент имеет значение; это значение является строкой:

"This sentence is the content of the p element."

альтернативно, мы можем вызвать <p> элемент, который будет отображаться путем установки свойства содержимого <p> элемент в CSS:

p { content: "This sentence is the content of the p element set in the CSS."; }

эти два способа введения строки в <p> элементы идентичны.

теперь подумайте о том, чтобы сделать то же самое с псевдоклассами:

HTML:
  <body>
      <p class="text-placeholder">P</p>
  </body>

CSS:
  p:before { content: "BEFORE... " ; }
  p:after { content: " ...and AFTER"; }

результат:

BEFORE...  P ...and AFTER

наконец, представьте, как бы вы выполнить этот пример без использование CSS. Это невозможно, потому что нет способа установить содержимое псевдокласса в разметке HTML.

вы можете быть творческим и представить, что что-то вроде этого может работать:

<p:before>BEFORE... </p>
<p> P </p>
<p:after> ...and AFTER</p>

но, это не, потому что <p:before> и <p:after> не являются HTML-элементами.

в заключение:

  • псевдо-классы существуют для каждого элемента разметки.
  • по умолчанию они невидимы, поскольку инициализируются без свойства content.
  • вы не можете установить свойство content для псевдо-классов с разметкой HTML.
    поэтому свойство содержимого псевдо-элементов должно быть объявлено с объявлениями CSS, чтобы для отображения.

причина, по которой вам нужен content: '' декларации для каждого ::before и/или ::after псевдо-элемент, потому что начальное значение content is normal, что эквивалентно none на ::before и ::after псевдо-элементы. Вижу spec.

причина начальное значение content - это не пустая строка, а значение, которое вычисляет none на ::before и ::after псевдо-элементы, двоится:

  1. имея пустой встроенное содержимое в начале и конце каждого элемента довольно глупо. Помните, что первоначальная цель ::before и ::after псевдо-элементы должны вставлять сгенерированное содержимое до и после основного содержимого исходного элемента. Когда нет содержимого для вставки, создание дополнительного поля просто для вставки ничего не имеет смысла. Так что none значение есть, чтобы сказать браузеру не беспокоиться о создании дополнительного окна.

    практика использования пустой ::before и ::after псевдо-элементы для создания дополнительных ящиков с единственной целью эстетики макета относительно новы, и некоторые пуристы могут даже зайти так далеко, чтобы назвать это взломом по этой причине.

  2. наличие пустого встроенного содержимого в начале и конце каждого элемента означает, что каждый (не замененный) элемент-включая html и body - по умолчанию будет генерировать не одну коробку, а до три ящики (и больше в случае элементы, которые уже генерируют больше, чем просто основное поле, например элементы со стилями списка). Сколько из двух дополнительных ящиков на элемент вы действительно будете использовать? Это потенциально утроение стоимость макета для очень небольшой прирост.

    реально, даже в этом десятилетии, менее 10% элементов на странице когда-либо понадобится ::before и ::after псевдо-элементы для макета.

и поэтому эти псевдо-элементы сделаны opt-in - потому что заставить их отказаться - это не только пустая трата системных ресурсов, но и просто нелогично, учитывая их первоначальную цель. Причина производительности также в том, почему я не рекомендуется генерировать псевдоэлементы для каждого элемента с помощью ::before, ::after.

но тогда вы можете спросить: почему нет display свойство по умолчанию для none on ::before, ::after? Просто: потому что начальное значение display не none; это inline. Имея inline кажется none на ::before, ::after не является опцией, потому что тогда вы никогда не сможете отобразить их в строке. Имея начальное значение display be none on ::before, ::after не является опцией, поскольку свойство может иметь только одно начальное значение. (Вот почему начальное значение content всегда normal и он просто определен для вычисления до none on ::before, ::after.)


пока вы не добавить content: ..., элемент psuedo на самом деле не exist.

установка других свойств стиля недостаточно, чтобы заставить браузер создать элемент.