Căn giữa theo chiều ngang trong CSS: hướng dẫn toàn diện

Căn giữa các phần tử trong CSS có lẽ là một trong các vấn đề mà người thiết kế giao diện hay phàn nàn nhất. Tại sao nó lại khó khăn như vậy?

Tôi nghĩ vấn đề không phải là nó quá khó thực hiện, mà là vì có rất nhiều cách khác nhau để làm điều đó- phụ thuộc vào tình huống cụ thể, cái khó ở đây là không biết đi theo hướng nào.

Vì thế chúng ta sẽ làm các phân loại và hy vọng việc lựa chọn sẽ dễ dàng hơn. Nào chúng ta cùng bắt đầu thôi!

Tôi cần căn giữa…


Theo chiều ngang (horizontally)

1. Liệu nó có phải là phần tử inline hoặc inline-* (chẳng hạn như văn bản hoặc liên kết)?

Bạn có thể căn giữa các phần tử inline theo chiều ngang trong phần tử bao là cấp khối (block-level), với dòng lệnh sau:

.center {text-align: center; }

Cái này hoạt động cho các thành phần kiểu inline, inline-block, inline-table, inline-flex, vân vân.

Mã mẫu ví dụ cho văn bản thuần:

<!DOCTYPE html>
<html>
    <head>
        <title>Văn bản đã căn giữa</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div {width:500px; 
                 border:1px solid black;
                 height:50px; text-align:center;}
        </style>    
    </head>
    <body>
        <div>Tôi cần căn giữa cái này</div>
    </body>
</html>

Hoặc cho liên kết:

<!DOCTYPE html>
<html>
    <head>
        <title>Liên kết đã căn giữa</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div {width:500px; 
                 border:1px solid black;
                 height:50px; text-align:center;}
        </style>    
    </head>
    <body>
        <div><a href="#">Đây là liên kết</a></div>
    </body>
</html>

Bạn cũng áp dụng được điều này với các thẻ h:

<!DOCTYPE html>
<html>
    <head>
        <title>Thẻ h2 đã căn giữa</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div {width:500px; 
                 border:1px solid black;
                 height:50px; text-align:center;}
        </style>    
    </head>
    <body>
        <div><h2>Đây là thẻ h2</h2></div>
    </body>
</html>

Ở đây chúng ta cần lưu ý, bản thân các thẻ h là block chứ không phải inline hay inline-*, thế tại sao nó vẫn căn giữa bằng lệnh trên được. Tôi chỉ có thể nói là vì nó cũng là văn bản, và text-align:center là căn giữa cho văn bản nên mặc dù thẻ h là block, tôi vẫn dùng câu lệnh trên được.

Bản thân các thẻ h có thể tự căn giữa chính nó trong thẻ div, ví dụ:

<!DOCTYPE html>
<html>
    <head>
        <title>Thẻ h2 đã tự căn giữa, chứ không cần thông qua div</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div {width:500px; 
                 border:1px solid black;
                 height:50px;}
            h2 {text-align:center;}
        </style>    
    </head>
    <body>
        <div><h2>Đây là thẻ h2</h2></div>
    </body>
</html>

Điều này cũng đúng y hệt với thẻ văn bản p, cũng là thẻ block.


Giờ là cho nút bấm dạng input submit hoặc button:

<!DOCTYPE html>
<html>
    <head>
        <title>Các nút bấm đã căn giữa</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div {width:500px; 
                 border:1px solid black;
                 margin-bottom:15px;
                 height:50px; text-align:center;}
        </style>    
    </head>
    <body>
        <div><input type="submit" value="Nút Submit"></div>
        <div><button>Nút Button</button></div>
    </body>
</html>

Có lẽ căn giữa văn bản bằng text-align:center là chỉ thị căn giữa mà nhiều người biết, phần sau sẽ ít người biết hơn.

2. Nó là phần tử dạng block

Bạn có thể căn giữa phần tử dạng block bằng cách cung cấp cho nó thuộc tính margin-leftmargin-rightauto (và nó phải được thiết lập chiều rộng width, nếu không nó sẽ có chiều rộng full của thẻ cha, và không thể căn giữa được). Cái này thường được giải quyết như thế này:

.centerMe {
margin: 0 auto;
 }

Ví dụ:

<!DOCTYPE html>
<html>
    <head>
        <title>Thẻ div đã căn giữa</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div#main {width:1000px; 
                 border:1px solid black;
                 margin-bottom:15px;
                 height:300px;}
            #centerMe {width:150px; height:150px; border:1px solid black; margin:0 auto;}
        </style>    
    </head>
    <body>
        <div id="main"><div id="centerMe">Tôi cần căn giữa thẻ div này</div></div>
    </body>
</html>

Khi bạn không thiết lập chiều rộng cho phần tử block, căn giữa sẽ thất bại, phần tử sẽ lấy luốn chiều rộng của phần tử cha, ví dụ:

<!DOCTYPE html>
<html>
    <head>
        <title>Căn giữa thất bại vì không thiết lập chiều rộng cho phần tử cần căn</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div#main {width:1000px; 
                 border:1px solid black;
                 margin-bottom:15px;
                 height:300px;}
            #centerMe {height:150px; border:1px solid black; margin:0 auto;}
        </style>    
    </head>
    <body>
        <div id="main"><div id="centerMe">Tôi cần căn giữa thẻ div này</div></div>
    </body>
</html>

Phương pháp căn giữa này sẽ hoạt động bất kể là chiều rộng của phần tử block mà bạn cần căn giữa hay phần tử cha của nó là bao nhiêu.

Lưu ý là bạn không thể đưa một phần tử float căn giữa được.

3. Có nhiều hơn một phần tử block

Nếu bạn có từ hai phần tử block trở lên cần được căn giữa trong một hàng, sẽ hiệu quả hơn nếu bạn biến đổi kiểu display của chúng. Dưới đây là một ví dụ về việc biến chúng thành dạng inline-block và một ví dụ về flexbox.

Ví dụ về inline-block:

<!DOCTYPE html>
<html>
    <head>
        <title>Căn giữa nhiều thành phần block với inline-block</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div#main {padding: 20px;
                 border:1px solid black;
                 margin-bottom:15px;
                 height:300px; text-align:center;}

            .centerMe {
                width:200px; 
                height:auto; 
                border:1px solid black; 
                padding:15px; 
                background-color:black; 
                color:#fcfcfc; 
                margin:10px; display:inline-block;}
            
        </style>    
    </head>
    <body>
        <div id="main">
            <div class="centerMe">Tôi cần căn giữa thẻ div này, liệu có thành công</div>
             <div class="centerMe">Tôi cần căn giữa thẻ div này. Tôi có nhiều chữ hơn người anh em của mình. Liệu có thành công</div>
             <div class="centerMe">Tôi cần căn giữa thẻ div này, liệu có thành công</div>
        </div>
    </body>
</html>

Ở đây chúng ta thực hiện hai việc:

  • Biến các div cần căn giữa vốn có thuộc tính display là block thành inline-block;
  • Để text-align của thẻ cha là center;

Lúc này chúng ta căn giữa như kiểu căn giữa văn bản đã nói ở phần đầu.

Khi bạn thu hẹp màn hình (thu hẹp kích cỡ của thẻ cha), các phần tử sẽ nhảy dòng nhưng vẫn sắp xếp để căn vào giữa.

Ví dụ về flex-box:

<!DOCTYPE html>
<html>
    <head>
        <title>Căn giữa nhiều thành phần block trên cùng dòng</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            div#main {padding: 20px;
                 border:1px solid black;
                 margin-bottom:15px;
                 height:300px;
                 display:flex; 
                 justify-content:center;}
            
            .centerMe {
                width:200px; 
                height:auto; 
                border:1px solid black; 
                padding:15px; 
                background-color:black; 
                color:#fcfcfc; 
                margin:10px;}
            
        </style>    
    </head>
    <body>
        <div id="main">
            <div class="centerMe">Tôi cần căn giữa thẻ div này, liệu có thành công</div>
             <div class="centerMe">Tôi cần căn giữa thẻ div này. Tôi có nhiều chữ hơn người anh em của mình. Liệu có thành công</div>
             <div class="centerMe">Tôi cần căn giữa thẻ div này, liệu có thành công</div>
        </div>
    </body>
</html>

Trong trường hợp này, thẻ cha cần bổ sung 2 thuộc tính, đó là:

display:flex; justify-content:center;

Các thẻ con không cần thêm thuộc tính gì.

Lúc này các thẻ con sẽ nằm trên cùng dòng và căn giữa dù bạn thu hẹp màn hình, nó như một kiểu responsive vậy, các cột tự động co giãn ngay cả khi đã được thiết lập chiều rộng cố định là 200px như ở trên.

Trong trường hợp bạn có nhiều phần tử cấp độ block muốn hiển thị theo kiểu xếp chồng lên nhau thì kỹ thuật margin auto vẫn dùng ổn.

<!DOCTYPE html>
<html>
    <head>
        <title>Căn giữa nhiều thành phần block với margin auto</title>
        <meta charset="UTF-8">
        <style>
            div#main {padding: 20px;
                 border:1px solid black;
                 margin-bottom:15px;
                 height:300px;}
            .centerMe {
                width:200px; 
                height:auto; 
                border:1px solid black; 
                padding:15px; 
                background-color:black; 
                color:#fcfcfc; 
                margin: 5px auto;}
            
        </style>    
    </head>
    <body>
        <div id="main">
            <div class="centerMe">Tôi cần căn giữa thẻ div này, liệu có thành công</div>
             <div class="centerMe">Tôi cần căn giữa thẻ div này. Tôi có nhiều chữ hơn người anh em của mình. Liệu có thành công</div>
             <div class="centerMe">Tôi cần căn giữa thẻ div này, liệu có thành công</div>
        </div>
    </body>
</html>

Ở đây khác là bạn không cần để margin:0 auto; mà chỉ cần để auto là đủ, số 0 có thể thay bằng giá trị khác. Như trường hợp trên là margin: 5px auto;


Kết luận

Bạn hoàn toàn có khả năng chủ động trong việc căn giữa mọi thứ theo chiều ngang trong CSS. Nhưng chúng ta cần lựa chọn các giải pháp phù hợp, chọn đúng mọi thứ sẽ ổn thỏa.

Chúng ta sẽ học cách căn giữa theo chiều dọc trong bài viết sau. Xin chào và hẹn gặp lại các bạn.

(Lược dịch từ bài viết Centering in CSS: A Complete Guide của tác giả Chris Coyier trên trang css-tricks)

Leave a Comment