Tạo mẫu lục giác lặp lại với CSS3


79

Vì vậy, tôi cần tạo một mẫu hình lục giác lặp lại, sử dụng CSS. Nếu cần hình ảnh, tôi có thể đến đó, nhưng tôi chỉ muốn sử dụng CSS nếu có thể.

Đây là ý tưởng về những gì tôi đang cố gắng tạo ra:

nhập mô tả hình ảnh ở đây

Về cơ bản, tôi chỉ cần một cách để tạo các hình lục giác, sau đó phủ văn bản / hình ảnh lên trên chúng. Tôi chưa có nhiều mã, vì tôi không thực sự chắc chắn nên bắt đầu từ đâu. Vấn đề là, tôi chỉ có thể sử dụng <div>s ở dạng hình lục giác như được hiển thị trong ( http://css-tricks.com/examples/ShapesOfCSS/ ), nhưng sau đó chúng sẽ không kết nối. Tôi có thể sử dụng một mẫu hình lục giác lặp lại, nhưng sau đó tôi sẽ không thể chỉ định vị trí chính xác của văn bản hoặc hình ảnh tôi cần trong các hình dạng cụ thể. Nhờ sự giúp đỡ trước.


2
Có mặt nạ CSS đang, nhưng sự hỗ trợ là khủng khiếp: webkit.org/blog/181/css-masks
mddw

Đối với cùng một mẫu hình lục giác bằng cách sử dụng <img>thẻ thay vì hình nền, bạn có thể kiểm tra Lưới hình lục giác bằng thẻ <img> .
web-tiki

Tôi đã tạo một phiên bản ngớ ngẩn của giải pháp ScottS để có các kích thước khác nhau một cách nhanh chóng. Kiểm tra Nó đây codepen.io/mort3za/pen/wBabaB
Morteza Ziyae

Câu trả lời:


130

(Mặc dù câu trả lời của Ana đến sau tôi vài tháng, có thể sử dụng câu trả lời của tôi làm cơ sở để "suy nghĩ từ", nhưng thực tế là cô ấy có thể đưa ra một phương pháp bằng cách sử dụng một đĩa đơn divrất đáng được quảng bá, vì vậy hãy xem câu trả lời của cô ấy - nhưng lưu ý rằng nội dung trong hệ lục phân bị hạn chế hơn.)

Đây là một câu hỏi thực sự tuyệt vời. Cảm ơn bạn đã hỏi nó. Điều tuyệt vời là thực tế rằng:

Fiddle này chứng tỏ bạn có thể làm được!

Fiddle gốc được sử dụng (được sửa đổi trong lần chỉnh sửa sau thành liên kết fiddle ở trên) - nó sử dụng hình ảnh imgur.com, có vẻ như không đáng tin cậy lắm khi tải, vì vậy fiddle mới đang sử dụng photobucket.com ( hãy cho tôi biết nếu có liên tục vấn đề tải hình ảnh ). Tôi đã giữ liên kết ban đầu vì mã giải thích bên dưới đi kèm với điều đó (có một vài khác biệt trong background-sizehoặc positionđối với fiddle mới).

Ý tưởng đến với tôi gần như ngay lập tức sau khi đọc câu hỏi của bạn, nhưng phải mất một thời gian để thực hiện. Ban đầu, tôi đã thử lấy một "hex" với một divphần tử giả và duy nhất , nhưng tốt nhất tôi có thể nói, không có cách nào để chỉ xoay background-image(mà tôi cần), vì vậy tôi phải thêm một số divphần tử bổ sung để có / bên trái của hex, để sau đó tôi có thể sử dụng các phần tử giả làm phương tiện background-imagequay.

Tôi đã thử nghiệm trong IE9, FF và Chrome. Về mặt lý thuyết, bất kỳ trình duyệt nào hỗ trợ CSS3 đều transformhoạt động được.

Cập nhật chính đầu tiên (giải thích thêm)

Bây giờ tôi có một chút thời gian để đăng một số giải thích về mã, vì vậy hãy tiếp tục:

Đầu tiên, hình lục giác được xác định bởi các mối quan hệ 30/60 độ và lượng giác, vì vậy đó sẽ là những góc quan trọng liên quan. Thứ hai, chúng ta bắt đầu với một "hàng" cho lưới hex nằm trong đó. HTML được định nghĩa là (các divphần tử bổ sung giúp tạo hex):

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

Chúng tôi sẽ sử dụng inline-blockcho hình lục giác display, nhưng chúng tôi không muốn chúng vô tình quấn vào dòng tiếp theo và làm hỏng lưới, vì vậy hãy white-space: nowrapgiải quyết vấn đề đó. Trên marginhàng này sẽ phụ thuộc vào bao nhiêu không gian bạn muốn giữa các hex và có thể cần một số thử nghiệm để đạt được những gì bạn muốn.

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

Sử dụng các phần tử con của .hexrowchúng chỉ là divphần tử, chúng tôi tạo cơ sở cho hình dạng hex. Ý widthchí hướng theo chiều ngang của đỉnh của hình lục giác, heightbắt nguồn từ số đó vì tất cả các cạnh có độ dài bằng nhau trên một hình lục giác đều. Một lần nữa, lề sẽ phụ thuộc vào khoảng cách, nhưng đây là nơi "chồng chéo" của các hình lục giác riêng lẻ sẽ xảy ra để làm cho hình dạng lưới xảy ra. Các background-imageđược định nghĩa một lần, ngay tại đây. Sự dịch chuyển sang trái trên nó là để chứa ít nhất chiều rộng được thêm vào cho phía bên trái của hình lục giác. Giả sử bạn muốn văn bản được căn giữa, các ô điều text-alignkhiển sẽ xử lý theo chiều ngang (tất nhiên) nhưng line-heightphù hợp với văn bản heightsẽ cho phép căn giữa theo chiều dọc.

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

Mỗi hex số lẻ chúng ta sẽ dịch chuyển xuống tương ứng với "hàng" và mỗi chữ số chẵn sẽ dịch chuyển lên. Tính toán dịch chuyển (chiều rộng x cos (30) / 2) cũng giống như (chiều cao / 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)) */
}

Chúng tôi đang sử dụng 2 divphần tử con để tạo "đôi cánh" của hex. Chúng có kích thước giống như hình chữ nhật lục giác chính, sau đó được xoay và đẩy "xuống dưới" hình lục giác chính. Background-imageđược kế thừa để hình ảnh giống nhau (tất nhiên), vì hình ảnh trong "cánh" sẽ được "xếp hàng" với hình ảnh đó trong hình chữ nhật chính. Các phần tử giả được sử dụng để tạo ra các hình ảnh, vì chúng cần được "xoay" lại theo chiều ngang (vì chúng tôi đã xoay phần tử gốc divcủa chúng để tạo ra "đôi cánh").

Cái :befoređầu tiên sẽ dịch nền của nó theo chiều rộng của lượng âm bằng phần chính của hex cộng với dịch chuyển nền ban đầu của hex chính. Điểm :beforethứ hai sẽ thay đổi điểm gốc của phép dịch và sẽ dịch chuyển chiều rộng chính trên trục x và một nửa chiều cao trên trục 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;
}

Đây là spannơi chứa văn bản của bạn. Việc line-heightđặt lại được đặt lại để làm cho các dòng văn bản bình thường, nhưng vertical-align: middlehoạt động vì dòng line-heightlớn hơn trên dòng chính. Các white-spaceđược thiết lập lại để cho phép gói lại. Lề trái / phải có thể được đặt thành âm để cho phép văn bản đi vào "cánh" của hệ lục phân.

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

Bạn có thể nhắm mục tiêu từng hàng và ô trong những hàng đó để thay đổi hình ảnh hoặc spancài đặt văn bản, độ mờ hoặc chứa một hình ảnh lớn hơn (để chuyển nó đến nơi bạn muốn), v.v. Đó là những gì sau đây làm cho hàng thứ hai.

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

1
Cảm ơn bạn đã đưa ra một câu trả lời được giải thích cặn kẽ, cặn kẽ và thiên tài, điều này thật tuyệt vời!
element119

@ScottS Mặc dù vậy, tôi đã gặp vấn đề kỳ lạ nhất khi triển khai nó. Tôi đang sử dụng bộ công cụ Bootstrap của Twitter, và bằng cách nào đó nó luôn xuất hiện như thế này . Tôi đã khắc phục vấn đề div.container: bố cục trở nên lộn xộn khi hình lục giác nằm trong div container này. Tuy nhiên, điều kỳ lạ là nhìn vào sự so sánh giữa mỗi kịch bản: liên kếtliên kết . Tôi đã chạy một số bài kiểm tra nhưng tôi không thể tìm ra điều gì làm rối tung các hình lục giác!
element119

@ Archio - Đầu tiên, bạn hiển thị mã cho con cấp một của hàng hex, nhưng vấn đề có thể xảy ra với con cấp hai đang tạo "cánh" của hex vì đó là phần của hình ảnh bị thiếu ( vì vậy tôi không thể gỡ lỗi). Vấn đề có thể đã ở đó (an overflow: hiddensẽ làm những gì bạn hiển thị), nhưng điều đó dường như không phải như vậy. Nhìn vào lồng cấp thứ hai div:beforemã của nó , bởi vì có thể divlà không xoay trong phép biến đổi, hoặc background-imagekhông kế thừa cho cả cái đó div:beforegiả của nó .
ScottS

Tôi vừa kiểm tra- cả hai dường như đều kế thừa màu nền ( liên kết ). Chúng cũng đang xoay, tôi có thể thấy rằng chúng được xoay trong trình kiểm tra Web của Chrome. Vấn đề là chúng không hiển thị, mặc dù chúng có display:block.
element119

Ah, tôi nghĩ rằng tôi đã tìm thấy nó! Có vẻ như vấn đề là z-index. Tôi đang điều chỉnh nó ngay bây giờ để đảm bảo mọi thứ hoạt động chính xác.
element119

53

Nó thực sự có thể được thực hiện chỉ với một phần tử cho mỗi hình lục giác và các phần tử giả cho hình nền và văn bản.

bản giới thiệu

Cấu trúc HTML cơ bản :

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

Bạn có thể có nhiều hàng hơn, bạn chỉ cần có nhình lục giác trên hàng lẻ và n+/-1hình lục giác trên hàng chẵn.

CSS có liên quan :

* { 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
Điều này thực sự xứng đáng nhận được nhiều ủng hộ hơn! Vì vậy, ngắn gọn và đơn giản, và bản demo thực sự cho thấy tính linh hoạt. Chỉ có một nhược điểm có thể là nội dung được lưu trữ trong một thuộc tính hơn là chính phần tử đó.
Thomas W

Bạn có thể đặt nội dung trong phần tử con :) Tôi chỉ muốn giảm thiểu số lượng phần tử HTML cần thiết ở đây. Nhưng một phần tử con với nội dung thực tế có thể được sử dụng dễ dàng thay cho phần tử giả.
Ana

2
Bạn nói đúng, về cơ bản chỉ yêu cầu thay thế .content:afterbằng .hexagon > *. Khéo léo.
Thomas W

bất kỳ suy nghĩ nào về cách các lề giữa các hình lục giác có thể được thay đổi một cách trang nhã?
tối đa

kỳ lạ là, nếu mở rộng thành toàn bộ các hình lục giác, điều này sẽ trở nên trục trặc trên safari, theo câu hỏi này
maxheld

2

Tôi sẽ cung cấp một bản demo đơn giản về cách tạo một hình lục giác.

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



1

Bạn có thể tạo một lưới lục giác hoàn toàn đáp ứng chỉ bằng CSS. Ý tưởng là tạo một hình dạng cha làm mặt nạ bằng cách sử dụng CSS2.1 tràn: ẩn tương thích với hầu hết các trình duyệt, ngay cả internet explorer 6.

Đây là một kỹ thuật đơn giản đáng ngạc nhiên có thể được sử dụng để tạo ra một mạng lưới đáp ứng với tất cả các loại hình dạng, nó chỉ yêu cầu suy nghĩ bên ngoài của hộp để giải quyết vấn đề.

Tôi có hướng dẫn từng bước chi tiết về cách thực hiện kỹ thuật này tại đây: https://www.codesmite.com/article/how-to-create-pure-css-hexagon-grids

Đây là cách tốt nhất mà tôi tìm thấy cho đến nay, không cần javascript và vừa linh hoạt vừa đáp ứng.

Tôi cũng đã sử dụng kỹ thuật này trong một mẫu HTML miễn phí bao gồm các hình ảnh bên trong các hình lục giác mà bạn có thể demo và tải xuống tại đây: https://www.codesmite.com/freebie/hexa-free-responsive-portfolio-template


0

nếu bạn có thể triển khai thủ thuật hình dạng div, thì chỉ cần cung cấp cho từng div một position:relative(ban đầu bạn sẽ phải định vị tất cả từng cái một, bằng cách đặt topleft)


Bạn có thể cho một ví dụ trong JSFiddle không? Thủ thuật hình khối div không thực sự hiệu quả, nếu tôi cần lấp đầy hình lục giác bằng hình ảnh và văn bản.
element119,

1
Vâng, bạn sẽ chỉ có thể tạo các hình dạng đơn màu: jsfiddle.net/Exceeder/cVqtW Sẽ không thể sử dụng div này làm vùng cắt cho hình nền hoặc để định hình văn bản.
Alex Pakka

-2

AFAIK, không có cách nào thực hiện trong CSS thuần túy. Đặt cược tốt nhất của bạn là sử dụng cắt mặt nạ cho nền như được giải thích ở đây: http://www.cssbakery.com/2009/06/background-image.html (điều này sẽ chỉ hoạt động nếu nền trang của bạn là màu đồng nhất hoặc bạn có thể vừa và định vị mặt nạ của bạn để phù hợp với nền trang.

Sau đó, bạn có thể sử dụng csstextwrap để phù hợp với văn bản: http://www.csstextwrap.com/examples.php

Có một loạt các câu hỏi tương tự trên SO. Vd: Có cách nào để văn bản trong div điền vào một hình tam giác không?


Alex, chỉ muốn bạn biết có một cách để làm trong CSS3 thuần túy (xem câu trả lời của tôi).
ScottS
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.