Cách căn giữa hộp đựng linh hoạt nhưng căn trái các mục linh hoạt


91

Tôi muốn các mục flex được căn giữa nhưng khi chúng ta có dòng thứ hai, phải có 5 (từ hình ảnh bên dưới) dưới 1 và không được căn giữa ở dòng chính.

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

Đây là một ví dụ về những gì tôi có:

ul {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0;
  padding: 0;
}
li {
  list-style-type: none;
  border: 1px solid gray;
  margin: 15px;
  padding: 5px;
  width: 200px;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>

http://jsfiddle.net/8jqbjese/2/

Câu trả lời:


79

Thử thách & Giới hạn Flexbox

Thách thức là căn giữa một nhóm các mục linh hoạt và căn trái chúng khi bọc. Nhưng trừ khi có số lượng hộp cố định trên mỗi hàng và mỗi hộp có chiều rộng cố định, điều này hiện không thể thực hiện được với flexbox.

Sử dụng mã được đăng trong câu hỏi, chúng ta có thể tạo một vùng chứa flex mới bao bọc vùng chứa flex hiện tại ( ul), cho phép chúng ta căn giữa ulvới justify-content: center.

Sau đó, các mục flex của ulcó thể được căn trái với justify-content: flex-start.

#container {
    display: flex;
    justify-content: center;
}

ul {
    display: flex;
    justify-content: flex-start;
}

Điều này tạo ra một nhóm các mục flex căn trái ở giữa.

Vấn đề với phương pháp này là ở một số kích thước màn hình nhất định sẽ có một khoảng trống ở bên phải của màn hình ul, khiến nó không còn xuất hiện ở giữa nữa.

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

Điều này xảy ra bởi vì trong bố cục flex (và trên thực tế, CSS nói chung) vùng chứa:

  1. không biết khi nào một phần tử kết thúc;
  2. không biết rằng không gian bị chiếm dụng trước đây hiện đang trống và
  3. không tính toán lại chiều rộng của nó để thu nhỏ lại bố cục hẹp hơn.

Độ dài tối đa của khoảng trắng ở bên phải là độ dài của mục linh hoạt mà vùng chứa mong đợi ở đó.

Trong bản demo sau, bằng cách định lại kích thước cửa sổ theo chiều ngang, bạn có thể thấy khoảng trắng đến và đi.

BẢN GIỚI THIỆU


Một cách tiếp cận thực tế hơn

Có thể đạt được bố cục mong muốn mà không cần sử dụng flexbox inline-blockcác truy vấn phương tiện .

HTML

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>

CSS

ul {
    margin: 0 auto;                  /* center container */
    width: 1200px;
    padding-left: 0;                 /* remove list padding */
    font-size: 0;                    /* remove inline-block white space;
                                        see https://stackoverflow.com/a/32801275/3597276 */
}

li {
    display: inline-block;
    font-size: 18px;                 /* restore font size removed in container */
    list-style-type: none;
    width: 150px;
    height: 50px;
    line-height: 50px;
    margin: 15px 25px;
    box-sizing: border-box;
    text-align: center;
}

@media screen and (max-width: 430px) { ul { width: 200px; } }
@media screen and (min-width: 431px) and (max-width: 630px) { ul { width: 400px; } }
@media screen and (min-width: 631px) and (max-width: 830px) { ul { width:600px;  } }
@media screen and (min-width: 831px) and (max-width: 1030px) { ul { width: 800px; } }
@media screen and (min-width: 1031px) and (max-width: 1230px) { ul { width: 1000px; } }

Đoạn mã trên hiển thị vùng chứa căn giữa theo chiều ngang với các phần tử con được căn trái như sau:

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

BẢN GIỚI THIỆU


Sự lựa chọn khác


3
Đúng vậy, rất nhiều điều mọi người muốn làm và cuối cùng sử dụng flexbox chỉ là tạo một lưới. May mắn thay, điều này sẽ được CSS Grids bao phủ khi phạm vi tiếp cận đó ở trạng thái hoàn thiện hơn.
TylerH

1
Đã liên kết bài đăng này với bài của bạn. Tôi có một phiên bản nữa trong đó cách giải quyết vấn đề tương tự, tuy nhiên, nó có thể là một bản dupe, vì vậy hãy xem và quyết định cho chính mình nếu bạn muốn đóng nó như vậy. Và cộng 1 cho lời giải thích tuyệt vời trong này.
Ason

Có lẽ một ý tưởng khác là thực hiện margin:0 autotrên trình bao bọc mẹ để mọi thứ được tập trung vào trang. Từ thời điểm đó, tất cả các thành phần con, (tức là vùng chứa linh hoạt đầu tiên) chỉ hoạt động theo quy trình hàng dòng bình thường? Có vẻ như điều này có thể được thực hiện đơn giản.
klewis

12

Bạn có thể đạt được nó với CSS Grid, chỉ cần sử dụng repeat(autofit, minmax(width-of-the-element, max-content))

ul {
       display: grid;
       grid-template-columns: repeat(auto-fit, minmax(210px, max-content));
       grid-gap: 16px;
       justify-content: center;
       padding: initial;
}

li {
    list-style-type: none;
    border: 1px solid gray;
    padding: 5px;
    width: 210px;
}
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
</ul>

http://jsfiddle.net/rwa20jkh/


Hấp dẫn. Nhưng không loại bỏ khoảng trống ở bên phải hoặc giữa lưới
Red

2
@Red Có một điều sai. Tôi đã thay đổi justify-items: centerđến justify-content:center, và bây giờ nó tập trung một cách hoàn hảo.
Joe82

Tôi không hiểu 210pxphần bên trong minmax. Làm cách nào để tôi thực hiện điều tương tự nhưng không có giới hạn giả tạo 210px? Không có hạn chế như vậy với flexbox. Tôi muốn kết quả chính xác giống như với flexbox, nhưng vùng nội dung phải được căn giữa giống như trong giải pháp của bạn.
Andrey Mikhaylov - lolmaus

1
Xin chào @ AndreyMikhaylov-lolmaus, phương pháp này hoạt động khi bạn muốn đặt chiều rộng cố định cho tất cả các phần tử. Trong câu hỏi, nó được diễn đạt là width:200px, và trong ví dụ của tôi, như tôi đã đặt width:210px, tôi cũng phải thêm điều đó vào minmaxphần
Joe82

@ Joe82 Cảm ơn bạn đã làm rõ! 🙏 Bạn có biết cách làm cho nó hoạt động với các phần tử có chiều rộng tùy ý không?
Andrey Mikhaylov - lolmaus

0

Như @michael đã đề xuất, đây là một hạn chế với flexbox hiện tại. Nhưng nếu bạn vẫn muốn sử dụng flexjustify-content: center;, thì chúng ta có thể giải quyết vấn đề này bằng cách thêm một liphần tử giả và gán margin-left.

    const handleResize = () => {
        const item_box = document.getElementById('parentId')
        const list_length  = item_box.clientWidth
        const product_card_length = 200 // length of your child element
        const item_in_a_row = Math.round(list_length/product_card_length)
        const to_be_added = item_in_a_row - parseInt(listObject.length % item_in_a_row) // listObject is the total number items
        const left_to_set = (to_be_added - 1 ) * product_card_length // -1 : dummy item has width set, so exclude it when calculating the left margin 
        const dummy_product = document.querySelectorAll('.product-card.dummy')[0]
        dummy_product.style.marginLeft = `${left_to_set}px`
    }
    handleResize() // Call it first time component mount
    window.addEventListener("resize", handleResize); 

Kiểm tra fiddle này (thay đổi kích thước và xem) hoặc video để tham khảo


0

Một cách để có được kiểu dáng mong muốn với lề là làm như sau:

#container {
    display: flex;
    justify-content: center;
}

#innercontainer {
    display: flex;
    flex: 0.9; -> add desired % of margin
    justify-content: flex-start;
}

0

Bạn có thể đặt các phần tử vô hình có cùng lớp với các phần khác (ví dụ như bị loại bỏ vì mục đích hiệu chỉnh) và chiều cao được đặt thành 0. Với điều đó, bạn sẽ có thể căn chỉnh các mục ở phần đầu của lưới.

Thí dụ

<div class="table-container">
  <div class="table-content">
    <p class="table-title">Table 1</p>
    <p class="mesa-price">$ 20</p>
  </div>
  
  <!-- Make stuff justified start -->
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
</div>

Kết quả

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


-1

Tôi đã gặp sự cố này khi viết mã bằng React Native. Có một giải pháp thanh lịch mà bạn có thể có bằng cách sử dụng FlexBox. Trong tình huống cụ thể của tôi, tôi đang cố căn giữa ba hộp linh hoạt (Flex: 2) bên trong một hộp khác bằng cách sử dụng alignItems. Giải pháp tôi đưa ra là sử dụng hai s trống, mỗi s có Flex: 1.

<View style={{alignItems: 'center', flexWrap: 'wrap', flexDirection: 'row'}}>
  <View style={{flex: 1}} />
    // Content here
  <View style={{flex: 1}} />
</View>

Đủ dễ dàng để chuyển đổi sang web / CSS.


Bạn đã hiểu sai câu hỏi. OP không hỏi cách căn giữa 3 mục, họ hỏi cách căn trái các mục trên hàng thứ 2 trong khi tất cả các mục căn giữa thành một nhóm và giải pháp của bạn không hiệu quả.
Ason
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.