Создайте сетку горизонтально и вертикально выровненных квадратов, которые не выходят за пределы контейнера и остаются квадратными при изменении размера

Критерии

  1. Ячейки не могут переполнять контейнер
  2. Макет должен работать для любого родительского размера и соотношения сторон (например, альбомный, портретный, x/y).
  3. Ячейки должны быть центрированы в своей строке и столбце (содержимое внутри ячейки не должно быть центрировано)
  4. В моем случае это должна быть сетка 2*8, но код должен быть достаточно гибким, чтобы обрабатывать сетки любого размера.
  5. Ячейки должны оставаться квадратными при изменении размера (сохраняйте указанное соотношение сторон 1/1).

Вот рабочее решение, которое мне удалось придумать (измените размер контейнера, чтобы увидеть, как он ведет себя при разных соотношениях сторон)

.grid {
    resize: both;
    width: 100px;
    height: 200px;
    border: 3px solid black;
    overflow: hidden;

    display: flex;
    flex-wrap: wrap;
}
.cell {
    display: flex;
    box-sizing: border-box;
    height: 25%;
    width: 50%;
    position: relative;
}
.inner {
    flex: 1;
    box-sizing: border-box;
    margin: auto;
    aspect-ratio: 1/1;
    max-height: 100%;
}
.content {
    box-sizing: border-box;
    border: 3px  solid blue;
    background-color: #8080ff;
    aspect-ratio: 1/1;
    max-height: 100%;
    margin: auto;
}
<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <meta http-equiv = "X-UA-Compatible" content = "IE=edge">
    <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class = "grid">
        <div class = "cell">
            <div class = "inner">
                <div class = "content"></div>
            </div>
        </div>
        <div class = "cell">
            <div class = "inner">
                <div class = "content"></div>
            </div>
        </div>
        <div class = "cell">
            <div class = "inner">
                <div class = "content"></div>
            </div>
        </div>
        <div class = "cell">
            <div class = "inner">
                <div class = "content"></div>
            </div>
        </div>
        <div class = "cell">
            <div class = "inner">
                <div class = "content"></div>
            </div>
        </div>
        <div class = "cell">
            <div class = "inner">
                <div class = "content"></div>
            </div>
        </div>
        <div class = "cell">
            <div class = "inner">
                <div class = "content"></div>
            </div>
        </div>
        <div class = "cell">
            <div class = "inner">
                <div class = "content"></div>
            </div>
        </div>
    </div>
</body>
</html>

Мое текущее решение функционально, но у меня есть несколько проблем с ним:

  1. Слишком много элементов оболочки (2 оболочки на ячейку). В идеале это должно быть уменьшено
  2. Я бы предпочел решение, которое использует display: grid;

Я пытаюсь изучить макет display: grid;, и это кажется проблемой, когда очевидным выбором будет сетка, но я еще не нашел решения, которое ее использует.

Решение, которое я предоставил, является эталонной реализацией того, как оно должно работать. Я ищу реализацию с таким же поведением, но с использованием display: grid;.

Вот моя попытка использовать сетку:

.grid {
    border: 3px solid black;
    resize: both;
    overflow: hidden;
    width: 100px;
    height: 200px;

    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(4, 1fr);
}
.cell {
    box-sizing: border-box;
    border: 2px solid red;
    background-color: rgb(255, 161, 161);
    max-height: 100%;
    overflow: hidden;
}
.content {
    margin: auto;
    box-sizing: border-box;
    border: 5px solid blue;
    background-color: rgb(136, 136, 255);
    aspect-ratio: 1/1;
    max-height: 100%;
}
<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <meta http-equiv = "X-UA-Compatible" content = "IE=edge">
    <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class = "wrap">
        <div class = "grid">
            <div class = "cell">
                <div class = "content"></div>
            </div>
            <div class = "cell">
                <div class = "content"></div>
            </div>
            <div class = "cell">
                <div class = "content"></div>
            </div>
            <div class = "cell">
                <div class = "content"></div>
            </div>
            <div class = "cell">
                <div class = "content"></div>
            </div>
            <div class = "cell">
                <div class = "content"></div>
            </div>
            <div class = "cell">
                <div class = "content"></div>
            </div>
            <div class = "cell">
                <div class = "content"></div>
            </div>
        </div>
    </div>
</body>
</html>

Как видите, мое решение сетки не удовлетворяет всем критериям. Ячейки не выровнены по вертикали в своей строке. Обычные способы вертикального выравнивания div ломали макет.

Возможно ли это даже с чистым макетом сетки CSS или использование flex/table/что-либо неизбежно?

Мое текущее решение работает отлично, но у меня есть несколько проблем с ним. это ли не оксюморон

Pete 10.01.2023 15:13

@Pete Это именно то, что я хочу, но с точки зрения качества кода у меня есть проблемы с ним.

kess 10.01.2023 15:15

Если вы хотите создать сетку, рекомендуется использовать display:grid… Как вы говорите, это уменьшит количество оберток и упростит ваш код. Я не уверен, в чем именно проблема? Вы пробовали использовать сетку?

Kokodoko 10.01.2023 15:20

@Kokodoko Если бы я не пытался использовать сетку, мне не пришлось бы делать этот пост, проблема с сеткой заключалась в том, что либо ячейки не сохраняли соотношение сторон, либо ячейки переполняли контейнер, либо ячейки были выровнен по вертикали сверху, а не посередине

kess 10.01.2023 15:23

Что касается упрощения кода, вы можете начать с удаления <div class = "grid">. Если я правильно понимаю, вы можете добавить display: flex; flex-wrap: wrap; к классу wrap, и поведение будет таким же.

Ivan Beliakov 10.01.2023 15:28

@IvanBeliakov Спасибо за отзыв! В реальном проекте у этой оболочки есть функция. Но в моем минимально воспроизводимом примере он теряет свою функцию и, следовательно, не нужен. Спасибо, что указали на это, я удалил это из поста.

kess 10.01.2023 15:48

@Kokodoko Я добавил свою попытку сетки в пост

kess 10.01.2023 15:48
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Настройка шаблона Metronic с помощью Webpack и Gulp
Настройка шаблона Metronic с помощью Webpack и Gulp
Я пишу эту статью, чтобы поделиться тем, как настроить макет Metronic с помощью Sass, поскольку Metronic предоставляет так много документации, и они...
Погружение в HTML и инструменты торговли
Погружение в HTML и инструменты торговли
Это была невероятная первая неделя в качестве стипендиата Bytewise Frontend Development Fellow, и я очень рад поделиться со всеми вами всем тем, чему...
Как создать страницу входа в систему с помощью HTML с использованием CSS.
Как создать страницу входа в систему с помощью HTML с использованием CSS.
Создание страницы входа в систему является важной частью создания веб-сайта или приложения, требующего аутентификации пользователя. Простую страницу...
Псевдоэлементы
Псевдоэлементы
Псевдоэлемент CSS - это ключевое слово, добавляемое к селектору, которое позволяет стилизовать определенную часть выбранного элемента (элементов)....
0
7
78
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Согласно документации по гибкому контейнеру MDN:

align-items: center;
justify-content: center;

Может центрироваться по вертикали

.grid {
    border: 3px solid black;
    resize: both;
    overflow: hidden;
    width: 100px;
    height: 200px;

    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(4, 1fr);
}
.cell {
    box-sizing: border-box;
    border: 5px solid red;
    background-color: rgb(255, 161, 161);
    max-height: 100%;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}
<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <meta http-equiv = "X-UA-Compatible" content = "IE=edge">
    <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class = "wrap">
        <div class = "grid">
            <div class = "cell">
                1
            </div>
            <div class = "cell">
                2
            </div>
            <div class = "cell">
                3
            </div>
            <div class = "cell">
                4
            </div>
            <div class = "cell">
                5
            </div>
            <div class = "cell">
                6
            </div>
            <div class = "cell">
                7
            </div>
            <div class = "cell">
                8<
            </div>
        </div>
    </div>
</body>
</html>

Цифры не обязательно должны быть центрированы, но синие квадраты, содержащие цифры, делают это. Также ваше решение полностью игнорирует требование соотношения сторон 1/1.

kess 10.01.2023 16:00

Я думаю, это проще, чем вы думаете, и вы ближе, чем вы думаете. В приведенном ниже фрагменте я удалил ненужные div-оболочки и добавил flexbox для центрирования содержимого ячейки.

.grid {
  border: 3px solid black;
  resize: both;
  overflow: hidden;
  display: grid;
  max-width: 200px;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(4, 1fr);
}

.grid > * {
  margin: auto;
  box-sizing: border-box;
  border: 5px solid blue;
  background-color: rgb(136, 136, 255);
  aspect-ratio: 1;
  max-height: 100%;
  width: 100%;
  overflow: hidden;
  
  /* center the cell content in both directions */
  display: flex;
  justify-content: center;
  align-items: center;
}
<div class = "grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
</div>

Спасибо! Это почти правильно, но ваше решение не сохраняет соотношение сторон 1/1, когда ширина больше высоты i.imgur.com/Z0grXRy.png

kess 10.01.2023 15:57

Также я хотел бы отметить, что числа в ячейке не имеют значения, их не нужно центрировать, извините, если я не совсем ясно выразился в своем сообщении. Я отредактировал его, чтобы больше не включать цифры.

kess 10.01.2023 16:24

Синий квадрат должен быть вертикально центрирован в своей строке, что правильно в вашем решении, но как только мы доберемся до соотношения сторон, при котором ширина больше высоты, ваше решение ломается.

kess 10.01.2023 16:26

@kess Я не вижу никаких проблем с тем, что соотношение сторон больше в ширину, чем в высоту; восемь ящиков остаются в центре. Включите проверку сетки в инструментах разработчика браузера и увидите пунктирные линии: i.stack.imgur.com/gDkgh.png Похоже, единственная проблема заключается в том, что восемь полей не остаются квадратными?

TylerH 10.01.2023 16:35

@TylerH «Похоже, единственная проблема, с которой вы столкнулись, это то, что восемь полей не остаются квадратными?» Да, это единственная проблема

kess 10.01.2023 16:53

@кесс Спасибо; Я добавил этот критерий в ваш список в вопросе, поскольку раньше он отсутствовал.

TylerH 10.01.2023 17:04

Извини. Пропустил изменяемый размер.

ray 12.01.2023 04:46
Ответ принят как подходящий

После нескольких часов проб и ошибок мне удалось найти решение.

Никаких оберток, никаких flexbox, никаких таблиц, никаких контейнерных запросов, только сетка и ее дочерние элементы.

.grid {
    border: 3px solid black;
    resize: both;
    overflow: hidden;
    display: grid;
    width: 100px;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(4, 1fr);
}

.cell {
    box-sizing: border-box;
    border: 5px solid blue;
    background-color: rgb(136, 136, 255);
    overflow: hidden;
    aspect-ratio: 1/1;
    
    /* keep the aspect ratio while filling as much space as possible */
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    padding: 0;
    margin: 0;
    
    /* center the element */
    position: relative;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
}
<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <meta http-equiv = "X-UA-Compatible" content = "IE=edge">
    <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class = "grid">
        <div class = "cell"></div>
        <div class = "cell"></div>
        <div class = "cell"></div>
        <div class = "cell"></div>
        <div class = "cell"></div>
        <div class = "cell"></div>
        <div class = "cell"></div>
        <div class = "cell"></div>
    </div>
</body>
</html>

Мне непонятно, почему сетке дается больше, чем ширина и количество столбцов. Настройка строк кажется избыточной, если мы установили высоту ячеек по отношению к их ширине (соотношение сторон: 1/1).

Этот фрагмент разделяет все до самого необходимого. Очевидно, что если вам нужно больше структуры, чтобы иметь дело с тем, что вы хотите поместить в ячейку, которую можно добавить, но она останется внутри ячейки и не имеет отношения к получению базового макета сетки, который вы хотите.

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  width: 100px;
  border: 3px solid black;
}

.grid>* {
  width: 100%;
  aspect-ratio: 1 / 1;
  border: solid blue 3px;
  box-sizing: border-box;
  background-color: #8080ff;
}
<!DOCTYPE html>
<html lang = "en">

<head>
  <meta charset = "UTF-8">
  <meta http-equiv = "X-UA-Compatible" content = "IE=edge">
  <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
  <title>Document</title>

</head>

<body>
  <div class = "grid">
    <div>
    </div>
    <div>
    </div>
    <div>
    </div>
    <div>
    </div>
    <div>
    </div>
    <div>
    </div>
    <div>
    </div>
    <div>
    </div>
  </div>
</body>

Другие вопросы по теме