Centering in CSS is well known for being a tedious task. It is kind of the running gag from the language, leading to jokes such as “we managed to send men on the moon, but we can’t vertically align in CSS”.
以CSS为中心是众所周知的一项繁琐的任务。 从语言上来说,这是种不断的插科打,,引起了这样的笑话,例如“我们设法将人送上月球,但我们无法在CSS中垂直对齐”。
While CSS is indeed a bit tricky when dealing with centering, especially vertical centering, I feel like those jokes are a bit unfair. Actually, there are plenty ways of centering content in CSS, you just have to know how to do it.
虽然CSS在处理居中,尤其是垂直居中时确实有些棘手,但我觉得这些笑话有点不公平。 实际上,有很多方法可以使CSS中的内容居中,您只需要知道如何做即可。
This article is not intended to explain how these methods work, but how we can wrap them in a Sass mixin for friendly and easy usage. So if you feel a bit uncomfortable with CSS centering, may I recommend a couple of resources to read beforehand:
本文的目的不是要解释这些方法的工作原理,而是如何将它们包装在Sass mixin中,以便于友好和轻松地使用。 因此,如果您对CSS居中感到不舒服,我是否可以建议您先阅读以下两个资源:
How To Center in CSS
如何在CSS中居中
Centering In CSS: A Complete Guide
以CSS为中心:完整指南
All good? Let’s get started then.
都好? 让我们开始吧。
First, we will focus on centering an element within its parent as it is the most common use case for absolute centering (modals, content in section, etc.). When you ask someone about CSS centering, the usual question you get as a reply is: do you know the element’s dimensions? The reason behind this question is that if you don’t know them, the best solution is to rely on CSS transforms. It lowers the browser support a bit, but it is highly flexible. If you can’t use CSS transforms or do know the element’s width and height, then it is easy to rely on negative margins.
首先,我们将集中于在其父元素内居中,因为它是绝对居中(模态,节中的内容等)最常见的用例。 当您向某人询问CSS居中时,您通常会得到一个答复: 您知道元素的尺寸吗? 这个问题背后的原因是,如果您不了解它们,最好的解决方案就是依靠CSS转换。 它降低了对浏览器的支持,但具有高度的灵活性。 如果您不能使用CSS转换或不知道元素的宽度和高度,则很容易依靠负边距。
So our mixin is going to basically do this: position the top left corner of the element absolutely in the middle of the container, then shift if back of half its width and half its height with either CSS transforms or negative margins depending on whether or not dimensions are passed to the mixin. No dimensions: go for transforms; dimensions: use margins.
因此,我们的mixin基本上将执行此操作:将元素的左上角绝对定位在容器的中间,然后根据CSS转换或负边距,根据元素的宽度或高度向后移动一半宽度和一半高度尺寸传递给混合。 没有维度:进行转换; 尺寸:使用边距。
You would then use it like this:
然后,您将像这样使用它:
/** * Enable position context for the child */ .parent { position: relative; } /** * Absolutely center the element in its parent * No dimensions are passed to the mixin, so it relies on CSS transforms */ .child-with-unknown-dimensions { @include center; } /** * Absolutely center the element in its parent * Width is passed to the mixin, so we rely on a negative margin for the * horizontal axis and CSS transforms for the vertical axis */ .child-with-known-width { @include center(400px); } /** * Absolutely center the element in its parent * Height is passed to the mixin, so we rely on a negative margin for the * vertical axis and CSS transforms for the horizontal axis */ .child-with-known-height { @include center($height: 400px); } /** * Absolutely center the element in its parent * Width is passed to the mixin, so we rely on a negative margins for both * horizontal axis and vertical axis */ .child-with-known-dimensions { @include center(400px, 400px); }When compiled, it should output this:
编译时,应输出以下内容:
§.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; }Okay, that looks a bit verbose but keep in mind that this output is for demonstration purpose. It is rather unlikely you find yourself using them all in a given situation.
好的,这看起来有些冗长,但请记住,此输出仅用于演示目的。 您很难在给定的情况下发现自己全部使用它们。
Okay, let’s dig. From the previous code snippets, we already know our mixin’s signature: it has two optional parameters, $width and $height.
好吧,让我们开始吧。 从前面的代码片段中,我们已经知道了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) { .. }Moving on. In all circumstances, the mixin needs to make the element absolutely positioned, so we can start with that.
继续。 在所有情况下,mixin都需要使元素绝对定位,因此我们可以从此开始。
@mixin center($width: null, $height: null) { position: absolute; top: 50%; left: 50%; // Moar magic here... }We will have to be clever with our code. Let’s pause here for a second and analyse the different options we have:
我们将必须对我们的代码更加聪明。 让我们在这里暂停一下,分析一下我们拥有的不同选项:
WidthHeightSolutionUndefinedUndefinedtranslateDefinedDefinedmarginDefinedUndefinedmargin-left + translateYUndefinedDefinedtranslateX + margin-top 宽度 高度 解 未定义 未定义 translate 已定义 已定义 margin 已定义 未定义 margin-left + translateY 未定义 已定义 translateX +上margin-topLet’s go with this.
让我们一起去吧。
@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` } }Now that we have set up the skeleton for our mixin, we only have to fill the gaps with actual CSS declarations.
现在我们已经为mixin设置了骨架,我们只需要用实际CSS声明来填补空白即可。
@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%); } }Note: the #{0 0} trick is a dirty hack to prevent a slightly to agressive minification from Sass that would lead to margin: mt 0 ml instead of margin: mt 0 0 ml.
注意: #{0 0}技巧是一个肮脏的技巧,目的是防止Sass产生轻微的侵略性缩小,从而导致margin: mt 0 ml而不是margin: mt 0 0 ml 。
So far, so good.
到目前为止,一切都很好。
There are several things we could do to push our mixin further, such as including a @supports rule inside the mixin to check for CSS transforms support or assume there is (or allow) Modernizr and output condition styles depending on whether or not CSS transforms are supported. We could also do some more agressive checking on the arguments to make sure they are valid values for width and height.
我们可以做一些事情来进一步推动mixin,例如在mixin中包含@supports规则以检查CSS转换的支持,或者根据CSS转换是否存在来假设是否有Modernizr和输出条件样式。支持的。 我们还可以对参数进行一些更具攻击性的检查,以确保它们是width和height有效值。
Although you have to ask yourself whether it’s a good thing to go that far. The mixin, as is, already has a cyclomatic complexity of 6, which is getting quite a lot for a Sass helper. It’s still okay, but adding more code to it likely means bumping the cyclomatic complexity further.
尽管您必须问自己,走那么远是否是一件好事。 像现在一样,mixin的圈复杂度已经为6,这对于Sass助手来说已经变得相当多了。 仍然可以,但是向其中添加更多代码可能意味着进一步提高循环复杂性。
I’m pretty sure some of you folks are jumping on your seat, thinking about how we can use Flexbox to center an element within its parent. Indeed, it’s possible and it turns out to be the easiest solution of all if you can afford it.
我敢肯定,有些人正在跳到您的座位上,思考如何使用Flexbox在其父元素中居中放置元素。 确实,这是有可能的,并且如果您负担得起的话,它是所有方法中最简单的解决方案。
The main difference between the solution we have just set up and the Flexbox one is that the latter is built on top of the parent while the former is mainly focusing on the child (provided any of its ancestors have a position different from static).
我们刚刚建立的解决方案与Flexbox的主要区别在于,后者是在父级之上构建的,而前者主要侧重于子级(前提是其祖先的position与static不同)。
To make an element have its child(ren) centered, you only have to print a triplet of properties. You can make a mixin, placeholder, class or whatever you fancy for this.
要使一个元素的子元素居中,只需打印三元组的属性即可。 您可以制作一个mixin,占位符,类或任何您喜欢的东西。
@mixin center-children { display: flex; justify-content: center; align-items: center; }Provided you add relevant vendor prefixes (through the mixin or Autoprefixer), this solution should Just Work in many browsers.
在提供您添加相关的供应商前缀(通过混入或Autoprefixer),该解决方案应该只是工作 很多浏览器 。
.parent { @include center-children; }Yielding, as you can surely guess:
您可以肯定地猜测:
.parent { display: flex; justify-content: center; align-items: center; }We wanted a short mixin to easily center an element within its parent; this one does the job, and it does it well. Not only is it clever enough to work no matter whether or not the element has specific dimensions, but it also provides a friendly and obvious API which is extremely important.
我们想要一个简短的mixin来轻松地将元素置于其父元素的中心。 这个人做得很好,而且做得很好。 无论元素是否具有特定的尺寸,它不仅足够聪明地工作,而且还提供了友好而明显的API,这非常重要。
By looking at the code, anybody understands right away that the @include center line is the inclusion of a helper that does some logic in order to make the element centered within its parent. However remember, the latter (or any parent in the DOM tree) has to have a position different than static for this to work! ;)
通过查看代码,任何人都可以立即理解@include center包含了一个帮助程序,该帮助程序执行一些逻辑以使元素居中于其父元素内。 但是请记住,后者(或DOM树中的任何父节点)必须具有不同于static的位置才能起作用! ;)
You can play with the code on SassMeister: http://sassmeister.com/gist/550809f5aa00b73d932c.
您可以在SassMeister上使用该代码: http ://sassmeister.com/gist/550809f5aa00b73d932c。
翻译自: https://www.sitepoint.com/centering-with-sass/
相关资源:zerofitness.github.io:一家健身中心,有兴趣让自己的脂肪适应-源码