歡迎光臨
每天分享高質量文章

使用 Sass mixin 實現 CSS 的居中效果

作者:Alsiso

網址:http://www.cnblogs.com/tugenhua0707/p/4722696.html

雖然使用 CSS 建立居中效果需要耍一些花招,特別是垂直居中效果,但我認為由此生出的詆毀,對於 CSS 則是不公平的。實際上我們有太多的方式使用 CSS 建立居中效果了,而且作為一名前端開發者,你真的有必要對其中的原理瞭解一二。

寫作本文的目的不是為了向各位解釋這些方法的工作原理,而是介紹將這些方法編寫為 Sass mixin 的方式,繼而將它們復用到各類專案中。如果你還不熟悉使用 CSS 建立居中效果的方法,我建議你仔細閱讀以下這篇文章:Centering In CSS: A Complete Guide。

總體概述

本文將會專註於解決子元素居中於父類容器的問題,就實踐經驗來說,這也是最常使用到的居中效果。當你請教別人 CSS 中和居中效果相關的問題時,他們往往會反問你:你知道元素具體的寬高嗎?之所以會有這樣的反問,是因為如果知道元素的寬高,那麼最好的解決方案就是使用 CSS transform 屬性。雖然該屬性在瀏覽器中的支援度稍低,但卻有著高度靈活的特性;如果因為瀏覽器相容性令你不能使用 CSS transform 屬性,或者也不知道元素的寬高,那麼實現居中效果的最簡單方法就是使用負向 margin。

我們今天要建立的 Sass mixin 就是基於上述的方法:將元素的左上角絕對定位到容器的中心位置,然後為 mixin 新增兩個可選引數,分別代表元素的寬高,如果傳遞了引數,那麼就使用負向 margin 的方法實現居中;如果沒有傳遞引數,就使用 CSS transform 的方法。

當我們的 Sass mixin 建立成功後,基本的使用方式如下所示:

/**

* 為子元素設定定位背景關係

*/

.parent {

position: relative;

}

/**

* 讓子元素絕對居中於父容器

* 沒有向 Sass mixin 傳遞引數,使用 CSS transform 屬性實現居中效果

*/

.child-with-unknown-dimensions {

@include center;

}

/**

* 讓子元素絕對居中於父容器

* 向 Sass mixin 傳遞了寬度,所以就使用負向 margin 處理水平位置,

* 使用 CSS transform 處理垂直位置

*/

.child-with-known-width {

@include center(400px);

}

/**

* 讓子元素絕對居中於父容器

* 向 Sass mixin 傳遞了高度,所以就使用負向 margin 處理垂直位置,

* 使用 CSS transform 處理水平位置

*/

.child-with-known-height {

@include center($height: 400px);

}

/**

* 讓子元素絕對居中於父容器

* 向 Sass mixin 傳遞了高度和寬度,所以就使用負向 margin 處理水平和垂直位置

*/

.child-with-known-dimensions {

@include center(400px, 400px);

}

上述 Sass 程式碼經過編譯之後,輸出結果如下:

.parent {

position: relative;

}

.child-with-unknown-dimensions {

position: absolute;

top: 50%;

left: 50%;

transform: translate(-50%, -50%);

}

.child-with-known-width {

position: absolute;

top: 50%;

left: 50%;

margin-left: -200px;

width: 400px;

transform: translateY(-50%);

}

.child-with-known-height {

position: absolute;

top: 50%;

left: 50%;

transform: translateX(-50%);

margin-top: -200px;

height: 400px;

}

.child-with-known-dimensions {

position: absolute;

top: 50%;

left: 50%;

margin-left: -200px;

width: 400px;

margin-top: -200px;

height: 400px;

}

還不錯,就是看起來有點囉嗦,不過鑒於是用來做 demo 的,也不必太過強求了。

建立 mixin

思路屢清楚了,下麵開工!根據上面的程式碼片段,我們已經知道了這個 mixin 的主要特徵:接收兩個可選的引數,用來表示元素的寬高($width 和 $height)。

/// Horizontal, vertical or absolute centering of element within its parent

/// If specified, this mixin will use negative margins based on element’s

/// dimensions. Else, it will rely on CSS transforms which have a lesser

/// browser support but are more flexible as they are dimension-agnostic.

///

/// @author Hugo Giraudel

///

/// @param {Length | null} $width [null] – Element width

/// @param {Length | null} $height [null] – Element height

///

@mixin center($width: null, $height: null) { .. }

然後,由分析知,要實現居中必須讓元素絕對定位:

@mixin center($width: null, $height: null) {

position: absolute;

top: 50%;

left: 50%;

}

在這裡讓我們暫停一下,深入分析後續邏輯的層次:

width height solution
null null translate
defined defined margin
defined null margin-left + translateY
null defined margin-right + translateX

秀程式碼:

@mixin center($width: null, $height: null) {

position: absolute;

top: 50%;

left: 50%;

@if not $width and not $height {

// Go with `translate`

} @else if $width and $height {

// Go width `margin`

} @else if not $height {

// Go with `margin-left` and `translateY`

} @else {

// Go with `margin-top` and `translateX`

}

}

透過上面的程式碼,我們已經搭好了 mixin 的骨架,只需要再新增上具體的邏輯程式碼即可:

@mixin center($width: null, $height: null) {

position: absolute;

top: 50%;

left: 50%;

@if not $width and not $height {

transform: translate(-50%, -50%);

} @else if $width and $height {

width: $width;

height: $height;

margin: -($width / 2) #{0 0} -($height / 2);

} @else if not $height {

width: $width;

margin-left: -($width / 2);

transform: translateY(-50%);

} @else {

height: $height;

margin-top: -($height / 2);

transform: translateX(-50%);

}

}

註意!上面程式碼中的 #{0 0} 實際上一種容錯措施,如果直接使用 0 0 的話,Sass 解析器會嘗試進行數值運算(在這裡會自動進行 0 -($height / 2) 的數學運算),進而導致我們得到 margin: mt 0 ml; 而不是想要得到的 margin: mt 0 0 ml;。

深入淺出

基本的功能實現後,我們還可以新增更多的特性,比如新增 @support 來檢查瀏覽器對 CSS transform 的支援度,進而可以根據 CSS transform 的支援度輸出相應的條件樣式。此外,我們還可以更嚴謹地去測試出入的引數是否是有效數值……

使用 Flexbox

看到 Flexbox 這個詞是不是就很興奮啊,少年!確實,使用 Flexbox 確實是最簡單的方式,它和前面方法主要的差別在於,使用 Flexbox 需要為父容器設定相關樣式,而使用前面的方法則主要是為子元素設定相關樣式(當然,父容器需要被設定為除 static 之外的任意 position)。

使用 Flexbox 實現子元素的居中效果,只需三行程式碼:

@mixin center-children {

display: flex;

justify-content: center;

align-items: center;

}

由於 Flexbox 還是比較新的屬性,那麼新增上相關的瀏覽器字首的話,會讓它擁有更廣泛的相容性。

.parent {

@include center-children;

}

正如你料想的那樣,就這麼簡單我們就實現了:

.parent {

display: flex;

justify-content: center;

align-items: center;

}

總結

我們就想要一個簡短的 mixin 讓元素在父容器中居中,我們做到了,而且做的更好。它不僅僅簡單易用無副作用,而且提供了良好的開發介面。

贊(0)

分享創造快樂