Genere un patrón hexagonal repetido con CSS3

79

Entonces, necesito hacer un patrón hexagonal repetido, usando CSS. Si se necesitan imágenes, puedo ir allí, pero preferiría usar CSS si es posible.

Aquí tienes una idea de lo que estoy intentando crear:

ingrese la descripción de la imagen aquí

Básicamente, solo necesito una forma de crear las formas hexagonales y luego superponer texto / imágenes encima de ellas. Todavía no tengo mucho código porque no estoy seguro de por dónde empezar. El problema es que podría usar <div>s en forma de hexágono como se muestra en ( http://css-tricks.com/examples/ShapesOfCSS/ ), pero entonces no se conectarían. Podría usar un patrón hexagonal repetido, pero entonces no podría especificar la ubicación exacta del texto o las imágenes que necesito en formas específicas. Gracias por cualquier ayuda de antemano.

element119
fuente
2
Hay máscaras CSS, pero el soporte es terrible: webkit.org/blog/181/css-masks
mddw
Para obtener el mismo patrón hexagonal usando la <img>etiqueta en lugar de una imagen de fondo, puede marcar Cuadrícula de hexágonos con la etiqueta <img> .
web-tiki
Hice una versión atrevida de la solución de ScottS para tener diferentes tamaños rápidamente. Compruébalo aquí codepen.io/mort3za/pen/wBabaB
Morteza Ziyae

Respuestas:

130

(Aunque la respuesta de Ana llegó meses después de la mía, probablemente usando la mía como base para "pensar desde", divvale la pena promocionar el hecho de que pudo idear un método usando una sola , así que revisa su respuesta también, pero tenga en cuenta que el contenido en el hexadecimal es más limitado).

Esta fue una pregunta realmente asombrosa. Gracias por preguntar Lo bueno es el hecho de que:

¡Este violín demuestra que puedes hacerlo!

Original Fiddle Used (modificado en la edición posterior del enlace de violín anterior): utilizó imágenes de imgur.com, que no parecían ser muy confiables en la carga, por lo que el nuevo violín está usando photobucket.com ( avíseme si hay imágenes persistentes problemas de carga de imágenes ). He mantenido el enlace original porque el código siguiente explicación va con eso (hay algunas diferencias en background-sizeo positional nuevo violín).

La idea se me ocurrió casi instantáneamente después de leer su pregunta, pero me tomó un tiempo implementarla. Originalmente intenté obtener un solo "hex" con un solo divy solo pseudo elementos, pero lo mejor que pude ver, no había forma de simplemente rotar el background-image(que necesitaba), así que tuve que agregar algunos divelementos adicionales para obtener el correcto / lados izquierdos del hexágono, para que luego pudiera usar los pseudo elementos como un medio de background-imagerotación.

Probé en IE9, FF y Chrome. En teoría, cualquier navegador que admita CSS3 transformdebería funcionar.

Primera actualización principal (explicación agregada)

Ahora tengo algo de tiempo para publicar una explicación del código, así que aquí va:

Primero, los hexágonos se definen por relaciones de 30/60 grados y trigonometría, por lo que esos serán los ángulos clave involucrados. En segundo lugar, comenzamos con una "fila" para que resida la cuadrícula hexadecimal. El HTML se define como (los divelementos adicionales ayudan a construir el hexadecimal):

<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>

Vamos a usar inline-blockpara el hexágono display, pero no queremos que pasen accidentalmente a la siguiente línea y arruinen la cuadrícula, así white-space: nowrapque resuelve ese problema. El marginde esta fila dependerá de cuánto espacio desee entre los hexágonos, y es posible que se necesite algo de experimentación para obtener lo que desea.

.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;
}

Usando los hijos inmediatos de los .hexrowque son solo divelementos, formamos la base para la forma hexagonal. La widthconducirá el horizontal de la parte superior de la hexagonal, la heightderiva de ese número desde todos los lados son de igual longitud en un hexágono regular. Nuevamente, el margen dependerá del espaciado, pero aquí es donde se producirá la "superposición" de los hexágonos individuales para que se produzca el aspecto de la cuadrícula. Se background-imagedefine una vez, aquí mismo. El cambio a la izquierda es para acomodar al menos el ancho adicional para el lado izquierdo del hexágono. Suponiendo que desea texto centrado, el text-alignmaneja el horizontal (por supuesto) pero el line-heightque coincide con el heightpermitirá un centrado vertical.

.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;
}

Cada extraña número hexadecimal que se va a desplazar hacia abajo en relación con la "fila" y cada incluso hacer el cambio. El cálculo de desplazamiento (ancho x cos (30) / 2) también es el mismo que (alto / 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)) */
}

Estamos usando 2 divelementos secundarios para crear las "alas" del hex. Tienen el mismo tamaño que el rectángulo hexagonal principal, y luego se giran y se empujan "debajo" del hexágono principal. Background-imagese hereda para que la imagen sea la misma (por supuesto), porque la imagen en las "alas" se "alineará" con la del rectángulo principal. Los pseudo elementos se utilizan para generar las imágenes, porque necesitan ser "rotados" de nuevo a la horizontal (ya que giramos el padre divde ellos para crear las "alas").

El :beforedel primero traducirá su fondo al ancho de la cantidad negativa igual a la parte principal del hexágono más el desplazamiento de fondo original del hexágono principal. El :beforedel segundo cambiará el punto de origen de la traslación y cambiará el ancho principal en el eje xy la mitad de la altura en el eje y.

.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;
}

Esto spanalberga su texto. Se line-heightrestablece para que las líneas de texto sean normales, pero vertical-align: middlefunciona ya que line-heightera más grande en el padre. Se white-spacereinicia para que permita volver a envolver. El margen izquierdo / derecho se puede establecer en negativo para permitir que el texto entre en las "alas" del hex.

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

Puede seleccionar filas y celdas individualmente en esas filas para cambiar las imágenes, la spanconfiguración del texto o la opacidad, o acomodar una imagen más grande (para cambiarla al lugar que desee), etc. Eso es lo que hace lo siguiente para la segunda fila.

.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
fuente
1
Gracias por dar una respuesta tan bien explicada, completa y genial, ¡esto es increíble!
element119
@ScottS Sin embargo, he tenido el problema más extraño al implementarlo. Estoy usando Bootstrap conjunto de herramientas de Twitter, y de alguna manera siempre aparece como este . He reducido el problema a div.container: el diseño se estropea cuando el hexágono está dentro de este contenedor div. Sin embargo, lo extraño es mirar la comparación entre cada escenario: enlace y enlace . ¡Hice algunas pruebas pero no puedo entender qué está arruinando los hexágonos!
element119
@ Archio - Primero, muestra el código para el hijo de primer nivel de la fila hexadecimal, pero es probable que el problema sea con los hijos de segundo nivel que están generando las "alas" del hexadecimal, ya que esa es la parte de la imagen que falta ( entonces no puedo depurar). El problema podría haber estado ahí (y overflow: hiddenharía lo que muestra), pero no parece ser así. Mire el anidamiento de segundo nivel divy su :beforecódigo, porque es probable que divno esté rotando en la transformación, o background-imageque no esté heredando tanto eso divcomo su :beforepseudoelemento.
ScottS
Acabo de comprobarlo: ambos parecen heredar el color de fondo ( enlace ). También están rotando, puedo ver que están rotados en el inspector de Chrome Web. El problema es que simplemente no se muestran, aunque sí display:block.
element119
¡Ah, creo que lo encontré! Parece que el problema fue z-index. Lo estoy modificando ahora para asegurarme de que todo funcione correctamente.
element119
53

En realidad, se puede hacer con un solo elemento por hexágono y pseudoelementos para la imagen de fondo y el texto.

manifestación

Estructura HTML básica :

<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>

Puede tener muchas más filas, solo necesita tener nhexágonos en filas impares y n+/-1hexágonos en filas pares.

CSS relevante :

* { 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); 
}
Ana
fuente
5
¡Esto realmente merece más votos a favor! Tan conciso y simple, y la demostración realmente muestra la versatilidad. El único inconveniente podría ser que el contenido se almacena en un atributo en lugar del elemento en sí.
Thomas W
Puede poner el contenido en un elemento secundario :) Solo quería minimizar la cantidad de elementos HTML necesarios aquí. Pero un elemento hijo con contenido real se puede usar fácilmente en lugar del pseudo.
Ana
2
Tienes razón, básicamente solo requiere reemplazarlo .content:aftercon .hexagon > *. Ingenioso.
Thomas W
¿Alguna idea sobre cómo se podrían alterar elegantemente los márgenes entre los hexágonos?
celebrado como máximo el
Curiosamente, si se expande a un montón de hexágonos, esto se vuelve un problema en el safari, según esta pregunta
maxheld
2

Proporcionaré una demostración simple de cómo crear una forma hexagonal.

.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
fuente
1

Puede crear una cuadrícula hexagonal totalmente receptiva utilizando solo CSS. La idea es crear una forma principal como una máscara usando CSS2.1 overflow: hidden que es compatible con casi todos los navegadores, incluso Internet Explorer 6.

Es una técnica sorprendentemente simple que se puede usar para crear una cuadrícula receptiva de todo tipo de formas, solo requiere pensar fuera de la caja para resolver el problema.

Tengo una extensa guía paso a paso sobre cómo hacer esta técnica aquí: https://www.codesmite.com/article/how-to-create-pure-css-hexagonal-grids

Esta es la mejor forma que he encontrado hasta ahora, no requiere javascript y es fluida y receptiva.

También utilicé la técnica en una plantilla HTML gratuita que incluye imágenes dentro de los hexágonos que puedes hacer una demostración y descargar aquí: https://www.codesmite.com/freebie/hexa-free-responsive-portfolio-template

Ceniza
fuente
0

si puede implementar el truco de las formas div, simplemente dé a cada div a position:relative(inicialmente tendría que colocarlos todos uno por uno al principio, estableciendo también topy left)

RozzA
fuente
¿Puede dar un ejemplo en un JSFiddle? El truco de las formas div no funciona realmente, si necesito llenar el hexágono con imágenes y texto.
element119
1
Sí, solo podrá crear formas de un solo color: jsfiddle.net/Exceeder/cVqtW No será posible usar estos div como regiones de recorte para imágenes de fondo o para dar forma al texto.
Alex Pakka
-2

AFAIK, no hay forma de hacerlo en CSS puro. Su mejor opción sería usar el recorte de máscara para los fondos como se explica aquí: http://www.cssbakery.com/2009/06/background-image.html (esto solo funcionará si el fondo de su página es de color sólido o si puede ajustar y coloque su máscara para que coincida con el fondo de la página.

Entonces puede usar csstextwrap para encajar en el texto: http://www.csstextwrap.com/examples.php

Hubo un montón de preguntas similares sobre SO. Por ejemplo, ¿ alguna forma de que el texto en div llene una forma de triángulo?

Alex Pakka
fuente
Alex, solo quería que supieras que hay una manera de hacerlo en CSS3 puro (mira mi respuesta).
ScottS