使用 CSS 网格布局创建的 3 个热门网站英雄
1:营销号召性用语(CTA)和图像
2:背景图片上的文本叠加
3:包含副本和表格的两列布局
这是系列文章的第十六篇,该系列文章探讨了过去 13 多年来我作为前端开发者所遇到的各种问题,并提出了相应的解决方案。访问ModernCSS.dev可以查看整个系列文章及其他资源。
本集探讨了如何创建网站英雄(又名“标题”),其中一种方式是使用 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
为网格容器,并创建一个名为“hero”的模板区域:
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
是我调整 Hero 尺寸的常用方法。它可以根据设备尺寸动态地调整 Hero 的尺寸,使其与用户的可视区域保持比例。
我们正在限制这个特定的值,以防止图像分辨率过度拉伸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%
新手
object-fit
?查看第 3 集(关于响应式图像)或第 6 集(关于动画图像标题)以获取更多示例。
最后,我们将添加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
用于垂直对齐网格子项
英雄 #1 演示
主角 #2:背景图片上的文字叠加
对于具有我们的基本 HTML 和 CSS 样式的此版本,图像完全遮挡了内容,因为它是 jpg,因此没有 alpha。
因此,第一步:将内容置于图像上方:
.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
包含 alpha 透明度的:
$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;
}
这样,我们就完成了第二个英雄!测试一下 demo,看看小视口版本是否还能正常工作:
英雄 #2 的技术总结
img
通过定义background-color
和添加到以将其滑到后面,header
在上方创建了一个彩色屏幕rgba
z-index: -1
img
header
- 使用伪元素来增加设计感,并将它们与父网格定义分开放置
place-self
英雄 #2 演示
英雄#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));
grid-gap: 2rem;
}
在第 8 集中了解有关此技术的更多信息:替换 12 列网格的解决方案
我们使用auto
来表示最大允许宽度,而不是 ,1fr
因为我们不希望列宽相等,而是希望列根据其相对大小按比例扩展。这样做是为了在文本内容和表单之间实现更好的视觉平衡,并且可以根据个人喜好进行调整。如果您希望列宽相等,请使用1fr
而不是auto
。
让我们花一点时间来讨论一下底部渐变边框 - 它是如何定位的?
它是:after
上的元素header
,也是我们使用包装器包裹主标题内容的主要原因。它被定位在 上place-self: end
,其宽度由自然拉伸行为决定。查看演示,了解其样式的极简性。
好的,现在我们需要在内容周围添加一些间距。在其他 Heroes 中,我们应用了 ,height
但这并不能完全满足我们的需求,因为在较小的视口中,表单和内容会垂直堆叠。
相反,这对于好老 来说是一个更好的工作padding
。我们将它放在 上,.hero__wrapper
以免影响 SVG 图案或渐变边框的位置:
.hero__wrapper {
// ...existing styles
padding: 10vmin 2rem;
}
使用视口单位vmin
作为顶部和底部填充意味着将使用“view-width”或“view-height”中较小的一个作为该值。这样做的好处是,有助于确保 Hero 不会覆盖较小视口的整个屏幕,这可能会使页面看起来没有额外的内容。这是因为在这种情况下,将使用“view-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
最小化较小视口的填充,并增加较大视口的填充
英雄#3 演示
奖励:使用clamp
缩小段落副本以适应视口大小,从而缩小段落副本以适应较小的视口。