CSS常見居中討論


      先來一個常見的案例,把一張圖片和下方文字進行居中:

      

      首先處理左右居中,考慮到img是一個行內元素,下方的文字內容也是行內元素,因此直接用text-align即可:

<style>
    .container{
        text-align: center;
    }
</style>
<div class="container">
    <img src="Mars.png">
    <p>火星</p>
</div>

      實際的效果如下:

火星

 

       這樣做的問題是,直接在最外層的container設置一個text-align的屬性,導致所有子元素都會繼承,假設圖片標題下方還有文字描述,那么這個文字描述也會被居中,如下所示:

火星

火星(Mars)是太陽系八大行星之一,天文符號是♂

       但實際上是希望文字描述向左對齊,這樣就不得不在文字描述添加一個text-align:left的屬性,覆蓋父元素的屬性,並且如果還有更多的子元素也需要這樣做,覆蓋屬性本身就是下策,因此這里采用其它的辦法。由於顯示的圖片是變化的,寬高是不定的,所以一般會顯示地給圖片設置一個寬高。如果知道寬度就可以用margin: 0 auto的方法,左右的margin值設置為auto,瀏覽器就會自動設置左右的margin值為容器剩余寬度的一半:

火星

火星(Mars)是太陽系八大行星之一,天文符號是♂

 代碼如下:

<style>
    figure{ width: 100px; margin: 0 auto;
    }
    figcaption{
        text-align: center;
    }
</style>
    <div class="container">
        <figure>
            <img src="Mars.png">
            <figcaption>火星</figcaption>
        </figure>
        <p class="desc">火星(Mars)是太陽系八大行星之一,天文符號是♂</p>
    </div>

  需要注意的是,這個辦法對上下居中不適用。

      使用margin: 0 auto可以說是最常見的左右居中方法,不僅適用於塊元素也適用於行內元素。很多網頁的布局都是主體內容固定寬度同時居中顯示,例如淘寶PC端:

 

       查看最外層的容器的樣式就可以發現使用了margin: 0 auto:

       接下來討論垂直居中,麻煩的是垂直居中。不過垂直居中有一個比較通用的辦法,那就是借助table-cell的垂直居中。方法是給父容器添加以下屬性:

.container{ 
    display: table-cell;
    vertical-align: middle;
}

      效果如下:

火星

      使用table-cell的缺點是容器的magin屬性失效了,因為margin不適用於表格布局。所以如果要把container居中的話,使用margin: 0 auto就不起作用了。解決的辦法是在container外層再套多一個容器,然后讓這個display為block的容器margin: 0 auto就可以了。

      另外一個缺點是table-cell的元素設置寬高為百分比的時候將不起作用,常見的場景是要將寬度設置為外層容器寬度的100%,解決辦法是將container的寬度設置成一個很大的值,例如3000px,這樣就達到100%的目的。還有一個問題是不兼容IE6/7,但現在生產環境基本上不需要兼容IE6/7了。

      這種方法有失效的時候,那就是container需要設置position為absolute時。因為設置position: absolute就會把(非flex)元素的display強制設置成block。解決辦法還是模仿上面的,外層再套多一個容器,將absolute作用於這個容器,副作用是設置內層container的height和width為百分比時會失效(除非將它的position也設置成absolute)。由於這個原因,導致有一種情況不能使用display: table-cell垂直居中。

      這種場景就是需要在頁面彈個框,這個框的位置需要在當前屏幕左右上下居中:

      通常需要將這個框的positiion設置成absolute,這個時候table-cell就不能發揮作用了,即使你在外面再套多兩層,最外層為absolute,里層為table-cell,但由於里層無法設置height為外層的100%,也就是說高度無法剛好占滿整個屏幕,所以不能起作用。

      解決辦法是使用relative定位,設置top為50%,再設置margin-top為元素高度的負的一半。一開始設置top 50%,將彈框的起始位置放到頁面中間,然后再設置margin-top為彈框高度的一半取負,這樣使得彈框在頁面中間位置再往上移一半自身的高度,這樣就剛好在正中間了,左右居中也可類似處理:

<style> 
    .mask{
        position: absolute; width: 100%; height: 100%;
    }
   .outer{ position: relative; top: 50%; left: 50%; margin-top: -100px; margin-left: -100px;
    }
    .container{
        width: 200px;
        height: 200px;
        display: table-cell;
        vertical-align: middle;
    }
</style>
<div class="mask">
    <div class="outer">
        <div class="container">

        </div>
    </div>
</div>

效果如下:

火星

       這種辦法的缺點是需要知道高度,無法根據內容長短自適應。所以就有了transform的方法,將margin-top一個具體的負值改成transform: translate(0, -50%),由於translate里面的面百分比是根據元素本身的高度計算的,於是就可以達到自適應的效果。將上面outer樣式改為:

   .outer{
        position: relative;
        top: 50%;
        left: 50%;
width: 200px; transform: translate(-50%, -50%); }

      這個辦法十分地方便,為了提高兼容性,需要添加-ms-和-webkit-前綴,缺點是IE8不支持。

      上面的兩種辦法:margin-top一個負值和translate -50%都有一個潛在的弊端, 就是如果設置left為50%是借助position為absolute的話,可能會導致換行:

<style>
    .container{
        position: relative;
    }
     .nav{
        position:absolute;
        left: 50%;
        transform: translate(-50%, 0);
        bottom: 0;
     }
</style>
<div class="container">
    <figure>    
        <img src="Mars.png">
    </figure>   
    <p class="nav"><span>地形</span><span>氣候</span><span>運動</span></p> 
</div>

      效果如下:

地形氣候運動

 

      可以看到,本來應該在一行顯示的p元素卻換行了,這是因為在一個relative元素里面absolute定位的子元素會盡可能地不超過容器的邊界,通過把行內元素換行的方式。由於設置left為50%,導致p元素超了邊界,所以就換行了,即使再translate -50%但已經晚了。即使是交換下兩者的位置也是一樣的效果,看得出瀏覽器執行的順序始終是以absolute的定位優先。所以這種方法還是有不適合的場景,主要是用於左右居中定位為absolute的的情況。

      另外一個CSS3居中的辦法是使用flex布局,flex布局居中十分容易和方便,只需要在父容器添加三行代碼,例如上面的居中情況,可將.nav的樣式改為:

    .nav{
        position:absolute;
        bottom: 0; display: flex; align-items: center; justify-content: center;
        width: 100%;
    }

      效果如下:

地形氣候運動

       flex布局在自適應領域的功能真的是非常強大,不過IE的兼容性不好,所以說可能的話,不要太去照顧IE了。

 

      上面討論的都是一些復合元素的居中,接下來分析單純的行內元素的垂直居中。

      主要是要借助vertical-align: middle。如下,有一張圖片和文字:

    <div class="container">
        <img src="Mars.png">
        <span>photo</span>
    </div>

      如果不做任何處理,那么默認的垂直居中是以baseline為基准:

photo

      為了讓它們能夠垂直居中,需要改變它們的居中方式:

        .container img,
        .container span{
            vertical-align: middle;
        }

      注意每個元素都需要設置,效果:

photo

       如果container的高度比圖片還要高:

photo

 

      為了讓中間的內容能夠在container里上下居中,可以設置文字的line-height為container的高度,那么文字就上下居中了,由於照片是和文字是垂直居中的,所以照片在container里也上下居中了,代碼:

        .container span{
            vertical-align: middle;
            line-height: 150px;
        }

      效果:

photo

       這也就給了一個啟示,如果需要垂直居中一個div里的比div高度小的照片,可以添加一個元素,讓它的line-height等於div的高度,如下:

<style>
        .container{
            width: 150px;
            height: 150px;
            text-align: center;
        }
       .container img{
            vertical-align: middle;
        } .container:before{
            content: "";
            vertical-align: middle; 
            line-height: 150px;
        }
</style>
<div class="container">
        <img style="vertical-align:middle;" src="Mars.png">
</div>

      或者是弄一個inline-block的元素,設置height為100%,這種的兼容性更好

        .container:before{
            content: "";
            display: inline-block;
            vertical-align: middle; 
            height: 100%;
        }

     上下居中效果:

 

       還有另外一種方法借助absolute定位和margin: auto

        .container{
            position: relative;
        }
       
        .container img{
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            margin: auto;
        }

      這個方法的神奇之處在於最后的margin: auto,這種方法也適用於div,但是需要給div顯式指定一個height,不然div的height會達到外層容器的100%。

      如果圖片比container大,這種方法就不適用了。因為有一種比較常見的場景是:照片有一邊和container一樣高,另外一邊按照片的比例縮放,照片居中顯示,超出的截斷,這種應該叫“占滿”(occupy)布局。這種情況,只需要把left/right/top/bottom/設成一個很大的負值即可:

        .container img{
            position: absolute;
            left: -9999px;
            top: -9999px;
            right: -9999px;
            bottom: -9999px;
            margin: auto;
        }
        .container{
            overflow: hidden;
        }

      效果:

      綜合上面的討論,左右居中常用text-align和margin: 0 auto,上下居中一種辦法是借助table-cell,另外一種是設置top: 50%和margin-top/translate(0, -50%)結合的辦法,還有就是使用flex布局,對於行內元素設置vertical-align: middle,同時借助一個高度為100%的元素達到垂直居中的效果。最后是position: absolute和margin: auto結合使用的辦法。可以說沒有一個方法可以100%適用,可以根據不同的情況合理結合使用。

      如果上文有不妥的地方,或者讀者有其它的居中方式,還請指出

   個人博客: http://yincheng.site/css-align

       參考:

1. How to vertically align an image inside div StackOverflow

2. A Complete Guide to Flexbox

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM