本集探讨了创建网站英雄--又称 "页眉"--用我最喜欢的一种方式来使用CSS网格布局:把它变成一个画布。
支持通知:这些技术中使用的基本属性--
grid-template-areas
和object-fit
--在IE 16以下不支持。好消息是--这仍然意味着它们有96%的支持率
受我多年从事营销工作的启发,以下是我们要创建的三个布局。
1:营销呼吁(CTA)和图像
2: 背景图片上的文字叠加
3:两栏式的文案和表格
基础HTML和CSS网格设置
在不远的过去,实现这些布局的方式大多需要使用position: absolute
。
有了网格,我们就可以从这个方案中升级,获得响应式的动态定位的超能力
这里是我们的HTML的起点:
<header>
<div class="hero__content">
<h1>Product</h1>
<p>You really need this product, so hurry and buy it today!</p>
<a href="#" class="button">Buy Now</a>
</div>
<img src="http://placecorgi.com/600" alt="" />
</header>
然后,我们将header
,变成一个网格容器,并创建一个名为 "英雄 "的单一模板区域:
header {
display: grid;
grid-template-areas: "hero";
}
使用模板区域创建一个单一的命名网格单元。然后我们创建一个规则,将所有任何类型的孩子(感谢通用选择器*
)分配到这个区域。
header {
// ...existing styles
> * {
grid-area: hero;
}
}
这个魔法是什么?
使用CSS网格布局模板区域意味着我们得到了网格定位的所有好处,这是对绝对定位的一次大升级
这使得所有的孩子都共享同一个网格单元,有效地把它变成一个画布。
我们现在可以定义项目居中或相对于彼此和容器的其他位置*,而不是*做数学计算百分比,或遇到媒体查询的麻烦,以绕过绝对定位干扰内容的响应式增长和收缩。
请继续阅读我们的标题例子,以获得更多的信息。
英雄 1:市场营销呼吁(CTA)和图像
除了我们的基础,还没有其他的样式,这里是我们的情况:元素在左上角对齐,图片分层在.hero__content
。
我们要解决的第一件事是在标题上设置一些尺寸预期:
header {
// ...existing styles
height: 65vh;
max-height: 600px;
}
视口单位,如vh
,是我对英雄尺寸的首选方式。这样可以根据设备的大小,动态地调整它们的大小,使它们与用户的观看区域相称。
我们为这个特定的单位设置了上限,以防止图片的分辨率通过max-height
,但这是可选的,并与所使用的图片有关。
接下来,我们需要对img
行为提供一些指导。
你可能想知道为什么我们没有使用背景图片。第一个答案是为了让图像保留其语义,包括alt
属性,以便于被辅助技术发现。
第二,将它保持为一个图像,可以使我们在样式和位置上有更大的灵活性。
我们将把object-fit
和object-position
一起使用,这实际上使它的初始行为与背景图像的行为非常相似:
img {
object-fit: cover;
object-position: 5vw -5vmin;
height: min(65vh, 600px);
width: 60%;
}
height: min(65vh, 600px)
很重要,因为它指示它根据这两个值中的任何一个的 "最小值 "来填充header
的高度,这个值来自我们在基础header
上设置的高度。在给出明确的尺寸参数后,object-fit
会接管并缩放图像内容以 "覆盖 "包括width: 60%
的尺寸。
最后,我们将添加justify-self
到img
,以定义它应该被放置在容器的end
- 我们第一次尝试使用网格来解决这个问题。
img {
// ...existing styles
justify-content: end;
}
下面是我们的进展:
现在对于.hero__content
,第一个改进是给它一个宽度定义,同时给它一些距离视口边缘的空间。
.hero__content {
margin-left: 5%;
max-width: 35%;
min-width: 30ch;
}
由于我们的img
被允许有60%的宽度,我们不希望我们的margin
和width
的组合超过40%,以避免重叠。
我们还提供了一个min-width
,以便在视口缩小时为内容保持合理的空间。
现在我们可以再次利用网格的使用,回到我们的header
规则,添加一个对齐属性:
header {
// ...existing styles
align-items: center;
}
这将使内容与图像垂直对齐。由于图像被设置为header
高度的100%,从视觉上看,这将使内容垂直居中,从而形成我们的桌面英雄。
为了使其在最小的屏幕上继续工作,我们需要做一些调整。
首先,我们将默认图像宽度为80%,并在媒体查询中包裹60%的减少。我们还将添加一个过渡,使其在视口调整之间变得平滑。
img {
// ...existing styles
width: 80%; // < update
transition: 180ms width ease-in;
@media (min-width: 60rem) {
width: 60%;
}
}
然后在内容上,我们将使用一些技巧,将背景设置为英雄背景的alpha,这样它只有在开始与图片重叠时才可见,并包括对边距的更新,一些填充,以及一些border-radius
。
.hero__content {
// ...existing styles
margin: 1rem 0 1rem 5%; // < update
z-index: 1;
background-color: rgba(mix(#fff, $primary, 97%), 0.8);
border-radius: 1rem;
padding: 0.5rem 0.5rem 0.5rem 0;
}
我们确实需要在那里添加一个小的z-index
,以使其高于img
,但这并不太痛苦!😊
这是最后的移动尺寸视口结果:
英雄#1#中的技术总结
object-fit
用来控制 的大小img
align-items: center
用来垂直对齐网格中的儿童
英雄#2背景图片上的文本叠加#
在这个版本的基础HTML和CSS样式中,图片完全遮盖了内容,因为它是一个jpg,所以没有alpha。
因此,第1步:将内容置于图片之上。
.hero__content {
z-index: 1;
}
接下来,我们将定义标题的尺寸。
header {
// ...existing styles
height: 60vh;
max-height: 600px;
}
再一次,我们将使用object-fit
来控制我们的img
。这次不同的是,我们想让它横跨100%的宽度和高度,这样它就可以完全覆盖在标题上:
img {
object-fit: cover;
height: min(60vh, 600px);
width: 100%;
}
在我们展示进度图之前,让我们调整一下网格子的排列:
header {
// ...existing styles
place-items: center;
}
这是目前的结果:
很明显,文字的对比度在背景图片上是不够的。一个常见的方法是在图像上应用彩色屏幕,这样既可以增加品牌效应,又可以帮助解决对比度问题。
下面是我们为实现这一目标而做的小改动--首先,header
,其中包括阿尔法透明的background-color
:
$primary: #3c87b3;
header {
// ...existing styles
background-color: rgba($primary, 0.7);
}
然后,我们用z-index
来引导图片滑到标题后面。在我的测试中,这仍然可以使img
被辅助技术发现,但如果你知道有这样的问题,请联系我们:
img {
// ...existing styles
z-index: -1;
}
结果如下:
为了更多地展示使用网格的可能性,让我们在:before
和:after
伪元素上创建一个header
,以容纳一个SVG模式。
要包括的重要事项是将这些伪元素也分配给grid-area: hero
。否则,它们会根据默认的网格流程作为新的 "行 "插入,这将破坏我们的画布:
&::before {
content: "";
grid-area: hero;
width: 50vmin;
height: 50vmin;
border-radius: 50%;
transform: translate(-10%, -10%);
background-image: url("data:image/svg+xml,%3Csvg width='14' height='14' viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='#{svgColor($support)}' fill-opacity='0.6' fill-rule='evenodd'%3E%3Cpath d='M5 0h1L0 6V5zM6 5v1H5z'/%3E%3C/g%3E%3C/svg%3E");
}
&::after {
content: "";
grid-area: hero;
width: 30vmin;
height: 60vmin;
transform: translate(20%, 40%) rotate(45deg);
background-image: url("data:image/svg+xml,%3Csvg width='14' height='14' viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='#{svgColor($support)}' fill-opacity='0.6' fill-rule='evenodd'%3E%3Cpath d='M5 0h1L0 6V5zM6 5v1H5z'/%3E%3C/g%3E%3C/svg%3E");
}
而由于place-items: center
的定义,结果就在这里了。
第一个要解决的问题是溢出问题,我们将用这个问题来解决:
header {
// ...existing styles
overflow: hidden;
}
接下来,网格提供了self
属性来指导那个特定的项目可以重新定位,这就把它从网格父定义中打破了。所以我们将相应地更新我们的伪元素:
&::before {
// ...existing styles
place-self: start;
}
&::after {
// ...existing styles
place-self: end;
}
就这样,我们已经完成了英雄2!测试一下演示,看看小视口版本是否继续良好地工作。
英雄2#中的技术总结
- 通过用
rgba
来定义header
的background-color
,并在img
上添加z-index: -1
,在img
上创建了一个彩色屏幕,将其滑到后面。header
- 使用伪元素来增加设计的亮点,并将它们与父网格定义分开,用
place-self
英雄#3带副本和表格的两栏式
在第三个例子中,我们的基础HTML做了一些改变,加入了表单。我们还在主要内容周围加入了一个封装器,我们将很快解释:
<header>
<div class="hero__wrapper">
<div class="hero__content">
<h1>Product</h1>
<p>You really need this product, so hurry and buy it today!</p>
</div>
<div class="hero__form">
<h2>Subscribe to Our Updates</h2>
<form action="/">
<label for="email">Enter your email:</label>
<input id="email" name="email" type="email" />
<button class="button" type="submit">Subscribe</button>
</form>
</div>
</div>
</header>
这是我们的起始外观,考虑到我们已经学到的东西:header
SVG模式的伪元素已经使用了place-self: end
,表单样式已经完好无损(破坏者:这也是在使用网格!),溢出也已经被控制了。
让我们开始解决这个问题,开始我们的.hero__wrapper
类。一个重要的更新是将它的宽度设置为100vw
,这样作为一个包含元素,它就能完全跨越标题。我们还将继续创建它作为一个网格容器。
.hero__wrapper {
width: 100vw;
display: grid;
}
接下来,是定义网格列的时候了。我们将使用我最喜欢的技术,这个技术已经在多期节目中介绍过,用于内在响应的网格列。
.hero__wrapper {
// ...existing styles
grid-template-columns: repeat(auto-fit, minmax(30ch, auto));
gap: 2rem;
}
我们使用auto
,而不是1fr
,因为我们不希望列数相等,而是希望列数能按比例扩展到其相对大小。这是为了在文本内容和表格之间取得更好的视觉平衡,并且可以根据口味进行调整。如果你想要等宽的列,请使用1fr
,而不是auto
。
让我们来谈谈底部的渐变边框--它是如何被定位的?
它是header
上的:after
元素,也是我们在主标题内容周围使用包装器的主要原因。它被定位在place-self: end
,它的宽度是由于自然拉伸行为。请看演示,看看它的风格是多么的简约。
好了,现在我们需要在内容周围增加一些间距。在另一个英雄中,我们应用了一个height
,但这并不能完全满足我们在这里的使用情况,因为在较小的视口上,表单和内容会垂直堆叠。
相反,这是一个更好的工作,适合于良好的padding
。我们将把它放在.hero__wrapper
,以便不影响SVG图案或梯度边框的位置。
.hero__wrapper {
// ...existing styles
padding: 10vmin 2rem;
}
使用视口单位vmin
作为顶部和底部的填充物,意味着将使用 "view-width "或 "view-height "中较小的值作为该值。这里的好处是帮助确保英雄不会覆盖较小视口的整个屏幕,这可能会使它看起来没有额外的页面内容。这是因为在这种情况下,"veiw-width "将被使用,使其成为一个较小的值,而在较大的桌面视口,它将使用 "view-height",成为一个较大的值。
为了完成大型视口的外观,我们将在包装器中添加两个定位值。
.hero__wrapper {
// ...existing styles
align-items: center;
justify-content: center;
}
其中,align-items
提供垂直对齐,而justify-content
提供水平对齐。
在较小的视口上,我们唯一的调整是确保内容在SVG图案上保持可读性。我们将使用与英雄#1类似的技术。
.hero__wrapper { // ...existing styles z-index: 1;}.hero__content { background-color: rgba(scale-color($primary, $lightness: 90%), 0.8); border-radius: 8px;}
英雄3#中的技术总结
- 使用包装器为内容与
header
设计元素提供一个二级网格布局。 - 创建具有自动宽度的列
grid-template-columns
- 利用
vmin
,在较小的视口上最小化填充,在较大的视口上增加填充。