Dưới đây là năm tùy chọn để đạt được bố cục này:
- Định vị CSS
- Flexbox với phần tử DOM vô hình
- Flexbox với phần tử giả vô hình
- Flexbox với
flex: 1
- Bố cục lưới CSS
Phương pháp # 1: Thuộc tính định vị CSS
Áp dụng position: relative
cho container flex.
Áp dụng position: absolute
cho mục D.
Bây giờ mặt hàng này được định vị tuyệt đối trong container flex.
Cụ thể hơn, mục D được xóa khỏi luồng tài liệu nhưng nằm trong giới hạn của tổ tiên định vị gần nhất .
Sử dụng các thuộc tính bù CSS top
và right
để di chuyển phần tử này vào vị trí.
li:last-child {
position: absolute;
top: 0;
right: 0;
background: #ddd;
}
ul {
position: relative;
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p {
text-align: center;
margin-top: 0;
}
span {
background-color: aqua;
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Một lưu ý cho phương pháp này là một số trình duyệt có thể không loại bỏ hoàn toàn một mục flex được định vị tuyệt đối khỏi luồng thông thường. Điều này thay đổi sự liên kết theo cách không chuẩn, bất ngờ. Thêm chi tiết: Mục flex được định vị tuyệt đối không bị xóa khỏi luồng bình thường trong IE11
Phương pháp # 2: Lề tự động Flex & Mục Flex vô hình (phần tử DOM)
Với sự kết hợp giữa các auto
lề và một mục flex mới, vô hình, bố cục có thể đạt được.
Mục flex mới giống hệt với mục D và được đặt ở đầu đối diện (cạnh trái).
Cụ thể hơn, vì căn chỉnh flex dựa trên sự phân bố không gian trống, vật phẩm mới là một đối trọng cần thiết để giữ ba hộp ở giữa được đặt ở giữa. Mục mới phải có cùng chiều rộng với mục D hiện có hoặc các hộp ở giữa sẽ không được căn giữa chính xác.
Các mục mới được loại bỏ khỏi xem với visibility: hidden
.
Nói ngắn gọn:
- Tạo một bản sao của
D
phần tử.
- Đặt nó ở đầu danh sách.
- Sử dụng flex
auto
lề để giữ A
, B
và C
làm trung tâm, với cả hai D
yếu tố tạo ra sự cân bằng bằng từ cả hai đầu.
- Áp dụng
visibility: hidden
cho bản saoD
li:first-child {
margin-right: auto;
visibility: hidden;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>D</li><!-- new; invisible spacer item -->
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Phương pháp # 3: Lợi nhuận tự động Flex & Mục Flex vô hình (phần tử giả)
Phương pháp này tương tự như # 2, ngoại trừ nó sạch hơn về mặt ngữ nghĩa và độ rộng của D
phải được biết.
- Tạo một phần tử giả có cùng chiều rộng với
D
.
- Đặt nó ở đầu container với
::before
.
- Sử dụng flex
auto
lề để giữ A
, B
và C
một cách hoàn hảo làm trung tâm, với giả và D
các yếu tố tạo ra sự cân bằng bằng từ cả hai đầu.
ul::before {
content:"D";
margin: 1px auto 1px 1px;
visibility: hidden;
padding: 5px;
background: #ddd;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Phương pháp # 4: Thêm vào các flex: 1
mục trái và phải
Bắt đầu với Phương pháp # 2 hoặc # 3 ở trên, thay vì lo lắng về chiều rộng bằng nhau cho các mục bên trái và bên phải để duy trì sự cân bằng như nhau, chỉ cần cung cấp cho mỗi mục flex: 1
. Điều này sẽ buộc cả hai phải tiêu thụ không gian có sẵn, do đó tập trung vào mục giữa.
Sau đó, bạn có thể thêm display: flex
vào các mục riêng lẻ để căn chỉnh nội dung của chúng.
LƯU Ý về việc sử dụng phương pháp này với min-height
: Hiện tại trong Chrome, Firefox, Edge và có thể các trình duyệt khác, quy tắc tốc ký đượcflex: 1
chia thành:
flex-grow: 1
flex-shrink: 1
flex-basis: 0%
Đơn vị phần trăm đó (%) trên flex-basis
khiến phương thức này bị hỏng khi min-height
được sử dụng trên container. Điều này là do, theo nguyên tắc chung, tỷ lệ phần trăm chiều cao ở trẻ em yêu cầu height
cài đặt thuộc tính rõ ràng trên cha mẹ.
Đây là một quy tắc CSS cũ có từ năm 1998 ( CSS Cấp 2 ) vẫn còn hiệu lực trong nhiều trình duyệt ở mức độ này hay mức độ khác. Để biết chi tiết đầy đủ xem tại đây và ở đây .
Dưới đây là một minh họa về vấn đề được đăng trong các bình luận của user2651804 :
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container>div {
background: orange;
margin: 5px;
}
#flex-container>div:first-child {
flex: 1;
}
#flex-container::after {
content: "";
flex: 1;
}
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
Giải pháp là không sử dụng đơn vị tỷ lệ phần trăm. Hãy thử px
hoặc hoàn toàn không có gì ( đó là những gì thông số kỹ thuật thực sự khuyến nghị , mặc dù thực tế là ít nhất một số trình duyệt chính đã gắn thêm một đơn vị tỷ lệ cho bất kỳ lý do gì).
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container > div {
background: orange;
margin: 5px;
}
/* OVERRIDE THE BROWSER SETTING IN THE FLEX PROPERTY */
#flex-container > div:first-child {
flex: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex: 1;
flex-basis: 0;
}
/* OR... JUST SET THE LONG-HAND PROPERTIES INDIVIDUALLY
#flex-container > div:first-child {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
*/
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
Phương pháp # 5: Bố cục lưới CSS
Đây có thể là phương pháp sạch nhất và hiệu quả nhất. Không cần định vị tuyệt đối, các yếu tố giả mạo hoặc các tin tặc khác.
Đơn giản chỉ cần tạo một lưới với nhiều cột. Sau đó định vị các mục của bạn trong cột giữa và cuối. Về cơ bản, chỉ để trống cột đầu tiên.
ul {
display: grid;
grid-template-columns: 1fr repeat(3, auto) 1fr;
grid-column-gap: 5px;
justify-items: center;
}
li:nth-child(1) { grid-column-start: 2; }
li:nth-child(4) { margin-left: auto; }
/* for demo only */
ul { padding: 0; margin: 0; list-style: none; }
li { padding: 5px; background: #aaa; }
p { text-align: center; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>| true center |</span></p>