Создайте повторяющийся шестиугольный узор с помощью CSS3

79

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

Вот идея того, что я пытаюсь создать:

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

По сути, мне просто нужен способ создать шестиугольные формы, а затем наложить на них текст / изображения. У меня пока немного кода, потому что я не совсем уверен, с чего начать. Проблема в том, что я мог бы просто использовать <div>s в форме шестиугольника, как показано на ( http://css-tricks.com/examples/ShapesOfCSS/ ), но тогда они не будут подключаться. Я мог бы использовать повторяющийся шестиугольник, но тогда я не смог бы указать точное местоположение текста или изображений, которые мне нужны в определенных формах. Спасибо за любую помощь заранее.

element119
источник
2
Есть маски CSS, но поддержка ужасная: webkit.org/blog/181/css-masks
mddw 08
Для того же шаблона шестиугольника с использованием <img>тега вместо фонового изображения вы можете проверить Сетка шестиугольников с тегом <img> .
web-tiki
Я сделал дерзкую версию решения ScottS, чтобы быстро иметь разные размеры. Проверьте это здесь codepen.io/mort3za/pen/wBabaB
Мортеза Зияе

Ответы:

130

(Хотя ответ Аны пришел через несколько месяцев после моего, вероятно, используя мой как основу для «размышлений», тот факт, что она смогла придумать метод с использованием сингла div, заслуживает внимания, так что посмотрите и ее ответ - но обратите внимание, что содержимое в шестнадцатеричном формате более ограничено.)

Это был действительно потрясающий вопрос. Спасибо, что спросили. Самое замечательное в том, что:

Эта скрипка доказывает, что вы можете это сделать!

Используемая оригинальная скрипка (измененная в более позднем редактировании ссылки на скрипку выше) - в ней использовались изображения imgur.com, которые не казались очень надежными при загрузке, поэтому новая скрипка использует photobucket.com ( дайте мне знать, есть ли постоянные проблемы с загрузкой изображений ). Я сохранил исходную ссылку, потому что приведенный ниже код объяснения идет с ней (есть несколько отличий в новой скрипке background-sizeили positionот нее).

Идея пришла ко мне почти сразу после прочтения вашего вопроса, но на реализацию потребовалось время. Изначально я пытался получить один «шестигранник» с одним divи только псевдоэлементами, но, насколько я могу судить, не было возможности просто повернуть background-image(что мне было нужно), поэтому мне пришлось добавить несколько дополнительных divэлементов, чтобы получить правильные / левые стороны шестиугольника, чтобы затем я мог использовать псевдоэлементы как средство background-imageвращения.

Я тестировал IE9, FF и Chrome. Теоретически transformон должен работать в любом браузере, поддерживающем CSS3 .

Первое основное обновление (добавлено объяснение)

У меня есть время, чтобы опубликовать объяснение кода, так что вот:

Во-первых, шестиугольники определяются отношениями 30/60 градусов и тригонометрией, поэтому это будут ключевые углы. Во-вторых, мы начинаем с «строки», в которой будет располагаться шестнадцатеричная сетка. HTML определяется как (дополнительные divэлементы помогают построить шестнадцатеричную сетку ):

<div class="hexrow">
    <div>
        <span>First Hex Text</span>
        <div></div>
        <div></div>
    </div>
    <div>
        <span>Second Hex Text</span>
        <div></div>
        <div></div>
    </div>
    <div>
        <span>Third Hex Text</span>
        <div></div>
        <div></div>
    </div>
</div>

Мы собираемся использовать inline-blockдля шестиугольника display, но мы не хотим, чтобы они случайно переносились на следующую строку и разрушали сетку, поэтому white-space: nowrapэта проблема решается. Значение marginв этой строке будет зависеть от того, сколько места вы хотите между шестигранниками, и могут потребоваться некоторые эксперименты, чтобы получить то, что вы хотите.

.hexrow {
    white-space: nowrap;
    /*right/left margin set at (( width of child div x sin(30) ) / 2) 
    makes a fairly tight fit; 
    a 3px bottom seems to match*/
    margin: 0 25px 3px;
}

Используя непосредственных дочерних элементов, .hexrowкоторые являются просто divэлементами, мы формируем основу для шестиугольной формы. Он widthбудет перемещаться по горизонтали вершины heightшестиугольника, полученный из этого числа, поскольку все стороны равны по длине в правильном шестиугольнике. Опять же, поле будет зависеть от интервала, но именно здесь произойдет «перекрытие» отдельных шестиугольников, чтобы создать вид сетки. background-imageОпределяется один раз, прямо здесь. Сдвиг влево на нем должен учесть как минимум добавленную ширину для левой стороны шестиугольника. Предполагая, что вам нужен центрированный текст, он text-alignобрабатывает горизонтальный (конечно), но тот, line-heightкоторый соответствует, heightбудет позволять вертикальное центрирование.

.hexrow > div {
    width: 100px;
    height: 173.2px; /* ( width x cos(30) ) x 2 */
    /* For margin:
    right/left = ( width x sin(30) ) makes no overlap
    right/left = (( width x sin(30) ) / 2) leaves a narrow separation
    */
    margin: 0 25px;
    position: relative;
    background-image: url(http://i.imgur.com/w5tV4.jpg);
    background-position: -50px 0; /* -left position -1 x width x sin(30) */
    background-repeat: no-repeat;
    color: #ffffff;
    text-align: center;
    line-height: 173.2px; /*equals height*/
    display: inline-block;
}

Каждый шестигранник с нечетным числом мы будем сдвигать вниз по отношению к «строке», а каждое четное - вверх. Расчет сдвига (ширина x cos (30) / 2) также такой же, как (высота / 4).

.hexrow > div:nth-child(odd) {
    top: 43.3px; /* ( width x cos(30) / 2 ) */
}

.hexrow > div:nth-child(even) {
    top: -44.8px; /* -1 x( ( width x cos(30) / 2) + (hexrow bottom margin / 2)) */
}

Мы используем 2 дочерних divэлемента для создания «крыльев» шестиугольника. Их размер такой же, как у основного прямоугольника шестиугольника, а затем они вращаются и помещаются «под» основным шестиугольником. Background-imageнаследуется, так что изображение остается таким же (конечно), потому что изображение в «крыльях» будет «выровнено» с изображением в основном прямоугольнике. Псевдоэлементы используются для генерации изображений, потому что их нужно «повернуть» обратно в горизонтальное положение (поскольку мы повернули их родительский элемент, divчтобы создать «крылья»).

:beforeИз первых будет переводить его фон ширину суммы отрицательной , равную основную часть гекса плюс исходного фонового сдвиг основного гекса. :beforeВторой изменит исходную точку перевода и переложить основную ширину на оси х, а половина высоты по оси у.

.hexrow > div > div:first-of-type {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: -1;
    overflow: hidden;
    background-image: inherit;

    -ms-transform:rotate(60deg); /* IE 9 */
    -moz-transform:rotate(60deg); /* Firefox */
    -webkit-transform:rotate(60deg); /* Safari and Chrome */
    -o-transform:rotate(60deg); /* Opera */
    transform:rotate(60deg);
}

.hexrow > div > div:first-of-type:before {
    content: '';
    position: absolute;
    width: 200px; /* width of main + margin sizing */
    height: 100%;
    background-image: inherit;
    background-position: top left;
    background-repeat: no-repeat;
    bottom: 0;
    left: 0;
    z-index: 1;

    -ms-transform:rotate(-60deg) translate(-150px, 0); /* IE 9 */
    -moz-transform:rotate(-60deg) translate(-150px, 0); /* Firefox */
    -webkit-transform:rotate(-60deg) translate(-150px, 0); /* Safari and Chrome */
    -o-transform:rotate(-60deg) translate(-150px, 0); /* Opera */
    transform:rotate(-60deg) translate(-150px, 0);

    -ms-transform-origin: 0 0; /* IE 9 */
    -webkit-transform-origin: 0 0; /* Safari and Chrome */
    -moz-transform-origin: 0 0; /* Firefox */
    -o-transform-origin: 0 0; /* Opera */
    transform-origin: 0 0;
}

.hexrow > div > div:last-of-type {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: -2;
    overflow: hidden;
    background-image: inherit;

    -ms-transform:rotate(-60deg); /* IE 9 */
    -moz-transform:rotate(-60deg); /* Firefox */
    -webkit-transform:rotate(-60deg); /* Safari and Chrome */
    -o-transform:rotate(-60deg); /* Opera */
    transform:rotate(-60deg);
}

.hexrow > div > div:last-of-type:before {
    content: '';
    position: absolute;
    width: 200px; /* starting width + margin sizing */
    height: 100%;
    background-image: inherit;
    background-position: top left;
    background-repeat: no-repeat;
    bottom: 0;
    left: 0;
    z-index: 1;

    /*translate properties are initial width (100px) and half height (173.2 / 2 = 86.6) */
    -ms-transform:rotate(60deg) translate(100px, 86.6px); /* IE 9 */
    -moz-transform:rotate(60deg) translate(100px, 86.6px); /* Firefox */
    -webkit-transform:rotate(60deg) translate(100px, 86.6px); /* Safari and Chrome */
    -o-transform:rotate(60deg) translate(100px, 86.6px); /* Opera */
    transform:rotate(60deg) translate(100px, 86.6px);

    -ms-transform-origin: 100% 0; /* IE 9 */
    -webkit-transform-origin: 100% 0; /* Safari and Chrome */
    -moz-transform-origin: 100% 0; /* Firefox */
    -o-transform-origin: 100% 0; /* Opera */
    transform-origin: 100% 0;
}

Здесь spanнаходится ваш текст. line-heightСбрасывается , чтобы строки текста нормально, но vertical-align: middleработает с line-heightбыло больше на родителей. white-spaceСбрасывается , так что позволяет оборачивать снова. Для левого / правого поля можно установить отрицательное значение, чтобы текст мог попасть в «крылья» шестиугольника.

.hexrow > div > span {
    display: inline-block;
    margin: 0 -30px;
    line-height: 1.1;
    vertical-align: middle;
    white-space: normal;
}

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

.hexrow:nth-child(2) > div:nth-child(1) {
    background-image: url(http://i.imgur.com/7Un8Y.jpg);
}

.hexrow:nth-child(2) > div:nth-child(1) > span {
    /*change some other settings*/
    margin: 0 -20px;
    color: black;
    font-size: .8em;
    font-weight: bold;
}

.hexrow:nth-child(2) > div:nth-child(2) {
    background-image: url(http://i.imgur.com/jeSPg.jpg);
}

.hexrow:nth-child(2) > div:nth-child(3) {
    background-image: url(http://i.imgur.com/Jwmxm.jpg);
    /*you can shift a large background image, but it can get complicated
    best to keep the image as the total width (200px) and height (174px)
    that the hex would be.
    */
    background-position: -150px -120px;
    opacity: .3;
    color: black;
}

.hexrow:nth-child(2) > div:nth-child(3) > div:before {
    /*you can shift a large background image, but it can get complicated
    best to keep the image as the total width (200px) and height (174px)
    that the hex would be.
    */
    background-position: -100px -120px; /* the left shift is always less in the pseudo elements by the amount of the base shift */
}

.hexrow:nth-child(2) > div:nth-child(4) {
    background-image: url(http://i.imgur.com/90EkV.jpg);
    background-position: -350px -120px;
}

.hexrow:nth-child(2) > div:nth-child(4) > div:before {
    background-position: -300px -120px;
}
ScottS
источник
1
Спасибо за такой хорошо объясненный, обстоятельный и гениальный ответ, это потрясающе!
element119
@ScottS Однако у меня возникла самая странная проблема с его реализацией. Я использую Bootstrap инструментарий Twitter, и почему - то всегда кажется , как это . Я сократил проблему до следующего div.container: макет становится беспорядочным, когда шестиугольник находится внутри этого контейнера div. Однако странно сравнить каждый сценарий: ссылку и ссылку . Я провел несколько тестов, но не могу понять, что не так с шестиугольниками!
element119
@ Archio - сначала вы показываете код для дочернего элемента первого уровня шестнадцатеричной строки, но проблема, скорее всего, связана с дочерними элементами второго уровня, которые генерируют «крылья» шестиугольника, так как это часть изображения, отсутствующая ( поэтому я не могу отлаживать). Проблема могла быть там (и overflow: hiddenделать то, что вы показываете), но, похоже, это не так. Посмотрите на вложение второго уровня divи его :beforeкод, потому что, вероятно, либо divне вращается в преобразовании, либо background-imageне наследуется как этому, так divи его :beforeпсевдоэлементу.
ScottS
Я только что проверил - похоже, они оба наследуют цвет фона ( ссылка ). Они также вращаются, я вижу, что они вращаются в веб-инспекторе Chrome. Проблема в том, что они просто не отображаются, хотя и есть display:block.
element119
Ах, кажется, я нашел! Похоже, проблема была z-index. Сейчас я настраиваю его, чтобы убедиться, что все работает правильно.
element119
53

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

демо

Базовая структура HTML :

<div class='row'>
    <div class='hexagon'></div>
</div>
<div class='row'>
    <div class='hexagon content ribbon' data-content='This is a test!!! 
    9/10'></div><!--
    --><div class='hexagon content longtext' data-content='Some longer text here.
       Bla bla bla bla bla bla bla bla bla bla blaaaah...'></div>
</div>

У вас может быть больше строк, вам просто нужно иметь n шестиугольники на нечетных строках и n+/-1шестиугольники на четных строках.

Соответствующий CSS :

* { box-sizing: border-box; margin: 0; padding: 0; }
.row { margin: -18.5% 0; text-align: center; }
.row:first-child { margin-top: 7%; }
.hexagon {
    position: relative;
    display: inline-block;
    overflow: hidden;
    margin: 0 8.5%;
    padding: 16%;
    transform: rotate(30deg) skewY(30deg) scaleX(.866); /* .866 = sqrt(3)/2 */
}
.hexagon:before, .content:after {
    display: block;
    position: absolute;
    /* 86.6% = (sqrt(3)/2)*100% = .866*100% */
    top: 6.7%; right: 0; bottom: 6.7%; left: 0; /* 6.7% = (100% -86.6%)/2 */
    transform: scaleX(1.155) /* 1.155 = 2/sqrt(3) */ 
               skewY(-30deg) rotate(-30deg);
    background-color: rgba(30,144,255,.56);
    background-size: cover;
    content: '';
}
.content:after { content: attr(data-content); }
/* add background images to :before pseudo-elements */
.row:nth-child(n) .hexagon:nth-child(m):before {
    background-image: 
        url(background-image-mxn.jpg); 
}
Ана
источник
5
Это действительно заслуживает большего количества голосов! Так кратко и просто, а демонстрация действительно демонстрирует универсальность. Единственным недостатком может быть то, что содержимое хранится в атрибуте, а не в самом элементе.
Thomas W
Вы можете поместить содержимое в дочерний элемент :) Я только хотел минимизировать количество необходимых здесь HTML-элементов. Но дочерний элемент с фактическим содержимым можно легко использовать вместо псевдо.
Ана,
2
Вы правы, в основном требуется только заменить .content:afterна .hexagon > *. Гениально.
Thomas W
какие-нибудь мысли о том, как элегантно изменить границы между шестиугольниками?
maxheld
как ни странно, если расширить до целой группы шестиугольников, это становится глючным на сафари, согласно этому вопросу
maxheld
2

Я покажу простую демонстрацию того, как создать шестиугольную форму.

.hex {
  width: 40px;
  height: 70px;
  margin: 20px;
  overflow: hidden;
}

.hex:before {
  content: "";
  transform: rotate(45deg);
  background: #f00;
  width: 50px;
  height: 50px;
  display: inline-block;
  margin: 10px -5px 10px -5px;
}
<div class="hex">
</div>

Starx
источник
1

Вот еще один подход с использованием COMPASS / SCSS, который позволяет легко установить размер и расположение шестиугольников:

http://codepen.io/interdruper/pen/GrBEk

Преступник
источник
1

Вы можете создать полностью адаптивную шестиугольную сетку, используя только CSS. Идея состоит в том, чтобы создать родительскую форму в виде маски с использованием CSS2.1 overflow: hidden, который совместим почти со всеми браузерами, даже с Internet Explorer 6.

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

У меня есть подробное пошаговое руководство по использованию этой техники здесь: https://www.codesmite.com/article/how-to-create-pure-css-hexagonal-grids

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

Я также использовал эту технику в бесплатном шаблоне HTML, который включает изображения внутри шестиугольников, которые вы можете продемонстрировать и загрузить здесь: https://www.codesmite.com/freebie/hexa-free-responsive-portfolio-template

Ясень
источник
0

если вы можете реализовать трюк с фигурами div, просто дайте каждому div a position:relative(сначала вам придется сначала расположить их все по одному, также установив topи left)

RozzA
источник
Вы можете привести пример на JSFiddle? Уловка с формами div не работает, если мне нужно заполнить шестиугольник изображениями и текстом.
element119 08
1
Да, вы сможете создавать только одноцветные фигуры: jsfiddle.net/Exceeder/cVqtW Невозможно использовать этот div в качестве областей обрезки для фоновых изображений или для формирования текста.
Alex Pakka
-2

AFAIK, в чистом CSS нет способа сделать это. Лучше всего использовать обрезку по маске для фона, как описано здесь: http://www.cssbakery.com/2009/06/background-image.html (это будет работать только в том случае, если фон вашей страницы сплошной или вы можете разместить и расположите маску в соответствии с фоном страницы.

Затем вы можете использовать csstextwrap, чтобы поместиться в текст: http://www.csstextwrap.com/examples.php

По SO была куча похожих вопросов. Например, есть ли способ, чтобы текст в div заполнял форму треугольника?

Алекс Пакка
источник
Алекс, просто хотел, чтобы вы знали, что есть способ сделать это на чистом CSS3 (см. Мой ответ).
ScottS