探索CSS單行文字居中,多行文字居左的實現方式

原文連接
github.com/XboxYan/not…css

好久之前

剛入前端那會,產品經理提出了這樣一個需求html

這段文字能不能這樣判斷一下,當文字不足一行時,讓它居中顯示,當文字超過一行就讓它居左,否則居中顯示很奇怪,由於最後一行是吊着的前端

image

琢磨了一下,當時我還真按照產品經理的邏輯,經過js判斷一下文字的高度,若是超過一行,就添加一個類名,並且這樣的文字不少地方都有,因此還作了遍歷,還有最重要的一點是關於方法執行的時機,有可能剛加載的時候高度還獲取不到(當時好像還用了定時器,還形成了先居中隨後居左跳動的現象)...css3

//僞代碼
$('.text').each(function(){
    if($(this).height()>30){
        $(this).addClass('mul');
    }
})
複製代碼

而後這些文本有可能仍是動態生成的,因此還得在生成文本的地方再調用一次這個方法,功能是作出來了,可別說有多囉嗦了,體驗也不咋地(雖然外面的人看不到)git

當時也在想,若是是CSS實現,那麼就徹底不用考慮這些問題了!github

關於CSS實現思路

其實只要你邏輯清晰,js都能實現出來,按照正常的思路一步一步走下來就好了。CSS可不是這樣,她須要你有更多的想象力。chrome

好比上面這種需求,表面上來看是須要判斷文本行數,這徹底不是CSS能幹的事呀,不過咱們能夠換個方向思考,文本默認是居左的(默認文本流),只有首行是居中的,首行能夠聯想到::first-line僞元素,因此能夠試着這樣實現一下segmentfault

<p>這段文字能不能這樣判斷一下,當文字不足一行時,讓它居中顯示,當文字超過一行就讓它居左</p>
複製代碼
p::first-line{
    text-align:center;
}
複製代碼

很好理解是吧,只針對首行進行居中操做,當多行時,首行已經鋪滿了,居中或者居左效果已經不明顯了,只是稍微有點瑕疵,首行的居中效果和後面的文字看着有些不太整齊的感受(由於當一行剩餘空間不足一個字符的時候會掉下去)wordpress

center1

解決這個問題也很簡單,上面的問題是因爲首行一直處於居中狀態,那有沒有什麼辦法能夠只要一行的時候才居中呢?這裏能夠藉助一下text-align-last,意思就是規定多行文本的最後一行的居中方式,若是和::first-line一塊兒使用,既要知足首行又要知足是最後一行,是否是就判斷出了當前只有一行呢?工具

p::first-line{/*匹配首行*/
    text-align-last:center;/*最後一行居中*/
}
複製代碼

center2

這下就正常了,有點首尾夾擊的味道~

See the Pen

遺憾的是,因爲::first-line支持樣式很是有限(MDN),上述實現方法僅在chrome下有效,不過這種邏輯仍是和js差異很大的

image

雖然上述並無text-align相關屬性,不過chrome卻已經支持了~

更好的實現方式

1.父級text-align:center,子級inline-block+text-align:left

首先來看看兼容性最好的實現方式

結構以下

<div class="content">
    <span class="text">這段文字能不能這樣判斷一下,當文字不足一行時,讓它居中顯示,當文字超過一行就讓它居左</span>
</div>
複製代碼

樣式以下

.content{
    text-align: center;
}
.text{
    display: inline-block;
    text-align: left;
}
複製代碼

這個方式最先是在《CSS世界》中學到的,

image

大概原理以下:

對於一個元素,若是其display屬性值是inline-block,那麼其寬度由內部元素決定,但永遠小於「包含塊」容器的尺寸,也就是「包裹性(shrink-to-fit)」

可能這樣描述的不夠直觀,來上述的案例簡單來說

  • 當文本比較少時,.text的寬度跟隨文本,而後咱們可使用父級text-align:center來使一個inline-block元素居中,因此能夠知足單行文本居中的效果,

  • 當文本比較多時,.text的寬度跟隨父級容器,因爲text-align:center會繼承下去,因此在.text上修復一下便可

See the Pen

兼容性一級棒~

2.width:fit-content+margin:auto

上述方式是經過父級text-align:center來實現inline-block居中的,很巧妙,可是額外增長了標籤,由於inline-block元素沒法自己居中的。

塊級block元素能夠在設置寬度後直接經過margin:0 auto來實現居中,可是必須指明寬度,否則就水平填充了,這二者的關係很微妙,有沒有什麼辦法可以讓塊級block元素的寬度像inline-block元素跟隨內部元素呢?

答案就是width:fit-content,詳細可參考這篇文章

width:fit-content能夠實現元素收縮效果的同時,保持本來的block水平狀態,因而,就能夠直接使用margin:auto實現元素向內自適應同時的居中效果了。

下面的實現方式均只須要單層標籤

<p class="text">這段文字能不能這樣判斷一下,當文字不足一行時,讓它居中顯示,當文字超過一行就讓它居左</p>
複製代碼
.text{
    width: fit-content;
    width: -moz-fit-content;//火狐須要-moz-前綴
    margin: 0 auto;
}
複製代碼

See the Pen

固然,這種特性IE確定是不支持的~

image

3.position:relative+transform

仍需設置display:inline-block來實現自適應,而後配合transform來實現水平方向居中效果,實現也很簡潔~

.text{
    display: inline-block;
    position: relative;
    left: 50%;
    transform: translateX(-50%);
}
複製代碼

See the Pen

4.display:table+margin:auto

前一種方式width:fit-content頗有效,IE不支持怎麼辦呢?其實默認display已經有這種特性了,當display屬性值是table,元素會表現出和width:fit-content的效果,既支持寬度跟隨內部元素,又支持水平方向上margin居中

.text{
    display: table;
    margin: 0 auto;
}
複製代碼

See the Pen

IE8也完美支持~

center3

5.flexgrid實現

對於flexgrid來講,實現這樣一個效果仍是挺容易的。

flex容器中,全部子項成爲彈性項,包括純文本節點(匿名盒子),就好像包裹了一層,因此很容易經過justify-content: center實現居中,同時(匿名盒子)也跟隨文本自適應寬度,當超過一行時,就按照默認的文本對齊方式。

grid同理,只不過對齊方式須要經過justify-items: center

  • flex實現
.text{
    display: flex;
    justify-content: center;
}
複製代碼

See the Pen

  • grid實現
.text{
    display: grid;
    justify-items: center;
}
複製代碼

See the Pen

相對於flexgrid的兼容性要差一些,因此儘可能選取flex方式,至少移動端和IE10(須要-ms-)是沒問題的

6.float實現

本覺得float實現不了的,感謝林小志提供了float居中的實現方法,大體原理以下:自己float元素是具有包裹特性的,主要難點在於如何居中,畢竟沒有float:center這種寫法,這裏主要用到兩層標籤,利用position:relative;left:50%正負抵消來實現

.content{
    position: relative;
    float: left;
    left: 50%;/**父級設置50%**/
}
.text{
    position: relative;
    float: left;
    left: -50%;/**子級設置-50%**/
}
複製代碼

See the Pen

略微繁瑣一點,不過也不失爲一種方法,兼容性也極好

小結

上述一共列舉了8種實現方式,固然第一種屬於實驗性質的,兼容性少的可憐,但也不失爲一種思路。怎麼想到這些方法呢?

第一就是聯想。好比上述提到了自適應(簡單來說就是尺寸由內容決定),我就想哪些能夠實現自適應呢?除了inline-block,還有floatposition:absolutedisplay:table等...首先float就排除了,元素設置了float後,總體居中實際上是件麻煩的事,幾乎不可能(通過試驗,能夠實現)。position:absolute仍是挺有但願的,藉助left:50%;transform:translateX(-50%)能夠實現居中效果, 嘗試了一番,發現寬度沒法自適應父級寬度,一樣失敗(說不定能夠,只是沒有想到)~~最後選擇了diaplay:table,也算是按部就班。flexgrid就更不用說了,自然就是爲彈性佈局而生了,實現這類效果不奇怪。

第二仍是基礎。CSS屬性可就那麼多,那只是停留在表面,不少看起來不相關的屬性在整個體系中又會有些微妙的關係,好比上面的width:fill-content,單獨看這個確定很雞肋,徹底能夠用inline-block來代替,可是他卻可讓一個普通的div元素具有inline-block的特性,不得不佩服CSS的設計~(確定有設計人員參與)

前一段時間在思考作一個可視化編輯工具,但願能夠經過一些屬性,就像photoshop那樣,直接做出一個頁面來,想一想看,發現只能做出最最基本的樣式,也就顏色,大小什麼的,若是要作成本文這樣一個效果,八成是作不了的,除了自己是作開發,別人怎麼可能知道這樣設置呢?可視化編輯工具的道路還很長很長,因此作前端的也無需擔憂被其餘什麼「一鍵生成工具」給取代了~

image

各位小夥伴若是還有其餘實現方式可在下方留言評論,若是文章有錯誤請及時指出,謝謝~

相關文章
相關標籤/搜索