Удалить псевдоэлемент, если есть только один дочерний элемент

Я использую невидимый псевдоэлемент (::after), который занимает последний слот в контейнере. Но если есть только один элемент, я бы хотел расположить его в центре.

Поэтому для этого мне нужно «удалить» псевдоэлемент в этом случае.

Как мне это сделать, если это возможно?

.main {
  background: #999;
  margin: 0 auto;
  width: 500px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
.box {
  background: #7ab9d7;
  color: #555;
  height: 30px;
  width: 30%;
  margin-bottom: 30px;
  text-align: center;
  font-size: 30px;
  padding-top: 120px;
}
.main::after {
  height: 0;
  width: 30%;
  content: "";
}
<div class="main">
  <div class="box">1</div>
</div>

P.S. Пример взят из здесь но уменьшил количество детей до 1.

P.S. P.S. Если много div'ов - выглядит так

введите здесь описание изображения

Если один div - выглядит так

введите здесь описание изображения


person Taras Yaremkiv    schedule 08.10.2017    source источник
comment
Как насчет удаления ширины: 30%?   -  person Vincent1989    schedule 08.10.2017
comment
Если есть только один .box, вы хотите удалить псевдоэлемент или центрировать его?   -  person karthikaruna    schedule 08.10.2017
comment
@karthikaruna удалить псевдоэлемент   -  person Taras Yaremkiv    schedule 08.10.2017
comment
В опубликованном универсальном решении, если только один элемент должен быть центрирован, это означает, что когда 2 или более они будут выровнены по левому краю. Я только что заметил в комментарии ниже, что теперь вы также говорите по центру один за другим. Означает ли это, что если их 2, они также должны быть центрированы, а не выровнены по левому краю? А если там 1 или 2 подряд своих?   -  person Ason    schedule 08.10.2017
comment
@LGSon Как правило, независимо от того, сколько элементов в строке: 1) если существует только одна строка, элементы должны быть центрированы в ней 2) если существуют две и более строк - в последней строке элементы должны быть выровнены по левому краю.   -  person Taras Yaremkiv    schedule 08.10.2017
comment
Я обновил свой ответ вторым универсальным решением, где также, когда 2 элемента, они будут правильно центрированы.   -  person Ason    schedule 08.10.2017


Ответы (4)


Как не отображать ::after содержимое, если один дочерний элемент у родителя?

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


Простым обходным решением было бы использование левого поля в сочетании с transform, когда есть только 1 элемент, здесь используется селектор only-child.

Можно было бы использовать и position: relative; left: 50%, хотя margin-left на одну строку меньше

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

Фрагмент стека

.main {
  background: #999;
  margin: 0 auto;
  width: 500px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.box {
  background: #7ab9d7;
  color: #555;
  height: 30px;
  width: 30%;
  margin-bottom: 30px;
  text-align: center;
  font-size: 30px;
  padding-top: 120px;
}

.main::after {
  height: 0;
  width: 30%;
  content: "";
}

.main div:only-child {                /*  added rule  */
  margin-left: 50%;
  transform: translateX(-50%);
}
<div class="main">
  <div class="box">1</div>
</div>
<br>
<div class="main">
  <div class="box">1</div>
  <div class="box">1</div>
</div>
<br>
<div class="main">
  <div class="box">1</div>
  <div class="box">1</div>
  <div class="box">1</div>
  <div class="box">1</div>
</div>
<br>


Обновлено на основе комментария, где, если есть 2 элемента, они также должны располагаться по центру.

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

С парой умных CSS-селекторов мы можем подсчитать если есть 1 или 2 элемента.

Это работает так, когда 1 или 2 элемента, используется автоматическое поле, а со свойством order элементы позиционируются после ::after, который теперь имеет ширину 100% и переместит элементы в новую строку, и там они не будут быть затронуты либо псевдо.

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

демонстрация скрипта

Фрагмент стека

.main {
  background: #999;
  margin: 0 auto;
  width: 500px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.box {
  background: #7ab9d7;
  color: #555;
  height: 30px;
  width: 30%;
  margin-bottom: 30px;
  text-align: center;
  font-size: 30px;
  padding-top: 120px;
}

.main::before {
  height: 0;
  width: 30%;
  content: "";
  order: 1;
}
.main::after {
  height: 0;
  width: 100%;
  content: "";
  order: 2;
}

/* new rules */

.main div:only-child,                            /* if 1 only */
.main div:first-child:nth-last-child(2) + div {  /* if 2, the 2nd*/
  order: 3;
  margin-left: auto;
  margin-right: auto;
}

.main div:first-child:nth-last-child(2) {         /* if 2, the 1st */
  order: 3;
  margin-left: auto;
}
<div class="main">
  <div class="box">1</div>
</div>
<br>
<div class="main">
  <div class="box">1</div>
  <div class="box">2</div>
</div>
<br>
<div class="main">
  <div class="box">1</div>
  <div class="box">2</div>
  <div class="box">3</div>
  <div class="box">4</div>
</div>
<br>
<div class="main">
  <div class="box">1</div>
  <div class="box">2</div>
  <div class="box">3</div>
  <div class="box">4</div>
  <div class="box">5</div>
</div>

person Ason    schedule 08.10.2017

Попробуй это. Обновлена ​​скрипта. Удален псевдоэлемент, который вы использовали в качестве заполнителя. Ниже представлен обновленный CSS.

.main {
  background: #999;
  margin: 0 auto;
  width: 500px;
  display: flex;
  flex-wrap: wrap;
}
.box {
  background: #7ab9d7;
  color: #555;
  height: 30px;
  width: 30%;
  margin-bottom: 30px;
  text-align: center;
  font-size: 30px;
  padding-top: 120px;
}
.box:not(:nth-child(3n)) {
  margin-right: 5%;
}
.box:only-child {
  margin-right: auto;
  margin-left: auto;
}

С несколькими .boxes

С одним .box

person karthikaruna    schedule 08.10.2017

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

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

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

Flexbox разработан для обеспечения гибкости за счет распределения свободного пространства. Как только вы начинаете ограничивать эту гибкость (например, заставляя flex-элемент оставаться в столбце, вводя поддельный элемент для удержания позиции), flexbox начинает ломаться.

Эта концепция далее объясняется здесь: Нацеливание гибких элементов на последнюю строку

Это проблема/ограничение, о котором знают люди в W3C, и это одна из причин, по которой они внедрили CSS Grid Layout, который решает эту проблему чисто и легко:

несколько элементов

.main {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 150px 150px;
  grid-row-gap: 30px;
  grid-column-gap: 3%;
  width: 500px;  
  background: #999;
  margin: 0 auto;
}

.box {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  text-align: center;
  background: #7ab9d7;
  color: #555;
  font-size: 30px;
}

.box:only-child {
  grid-column: 2 / 3;
}
<div class="main">
  <div class="box">1</div>
  <div class="box">2</div>
  <div class="box">3</div>
  <div class="box">4</div>
  <div class="box">5</div>
</div>

отдельный элемент

.main {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 150px 150px;
  grid-row-gap: 30px;
  grid-column-gap: 3%;
  width: 500px;  
  background: #999;
  margin: 0 auto;
}

.box {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  text-align: center;
  background: #7ab9d7;
  color: #555;
  font-size: 30px;
}

.box:only-child {
  grid-column: 2 / 3;
}
<div class="main">
  <div class="box">1</div>
</div>

демонстрация jsFiddle

person Michael Benjamin    schedule 08.10.2017

Для этого сначала вам нужно удалить ::after, затем вам нужно будет justify-content: center; по умолчанию и нацелить каждое последнее поле на левый центр, используя margin: 0 auto 30px 0;

Однако последнее поле также может быть первым полем, чтобы перезаписать это использование:

   .box:first-child {
        margin: 0 auto 30px auto !important;
    }

Чтобы получить дополнительные отступы в каждом поле, вам нужно будет добавить дополнительные div и отдельно добавить синий фон.

.main {
  background: #999;
  margin: 0 auto;
  width: 500px;
  display: flex;
  flex-wrap: wrap;
  /*justify-content: space-between;*/
  justify-content: center;
  align-items: center;

}
.box {
    background: #7ab9d7;
    color: #555;
    height: 30px;
    /* width: 30%; */
    margin-bottom: 30px;
    text-align: center;
    font-size: 30px;
    padding-top: 120px;
    /* flex: auto; */
    /* flex: 1; */
    flex-basis: 33.33%;
}

.box:last-child{
   margin: 0 auto 30px 0;
}

.box:first-child {
    margin: 0 auto 30px auto !important;
}
/*
.main::after {
  height: 0;
  width: 30%;
  content: "";
}
*/
<div class="main">
  <div class="box">1</div>
  <div class="box">2</div>
  <div class="box">3</div>
  <div class="box">4</div>
  <div class="box">5</div>
</div>

person Vincent1989    schedule 08.10.2017
comment
jsfiddle.net/3m9ad0sd это выглядит так, и я бы хотел, чтобы это выглядело как строки - например этот jsfiddle.net/9nw1bxoz - person Taras Yaremkiv; 08.10.2017