3个用CSS网格布局创建的热门网站英雄(附代码示例)

44 阅读5分钟

本集探讨了创建网站英雄--又称 "页眉"--用我最喜欢的一种方式来使用CSS网格布局:把它变成一个画布。

支持通知:这些技术中使用的基本属性--grid-template-areasobject-fit --在IE 16以下不支持。好消息是--这仍然意味着它们有96%的支持率

受我多年从事营销工作的启发,以下是我们要创建的三个布局。

1:营销呼吁(CTA)和图像

preview of marketing hero

2: 背景图片上的文字叠加

preview of text overlay hero

3:两栏式的文案和表格

preview of two-column hero

基础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)和图像

preview of marketing hero

除了我们的基础,还没有其他的样式,这里是我们的情况:元素在左上角对齐,图片分层在.hero__content

initial state of the base marketing hero

我们要解决的第一件事是在标题上设置一些尺寸预期:

header {
  // ...existing styles
  height: 65vh;
  max-height: 600px;
}

视口单位,如vh ,是我对英雄尺寸的首选方式。这样可以根据设备的大小,动态地调整它们的大小,使它们与用户的观看区域相称。

我们为这个特定的单位设置了上限,以防止图片的分辨率通过max-height ,但这是可选的,并与所使用的图片有关。

接下来,我们需要对img 行为提供一些指导。

你可能想知道为什么我们没有使用背景图片。第一个答案是为了让图像保留其语义,包括alt 属性,以便于被辅助技术发现。

第二,将它保持为一个图像,可以使我们在样式和位置上有更大的灵活性。

我们将把object-fitobject-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-selfimg ,以定义它应该被放置在容器的end - 我们第一次尝试使用网格来解决这个问题。

img {
  // ...existing styles
  justify-content: end;
}

下面是我们的进展:

marketing hero progress with image styles

现在对于.hero__content ,第一个改进是给它一个宽度定义,同时给它一些距离视口边缘的空间。

.hero__content {
  margin-left: 5%;
  max-width: 35%;
  min-width: 30ch;
}

由于我们的img 被允许有60%的宽度,我们不希望我们的marginwidth 的组合超过40%,以避免重叠。

我们还提供了一个min-width ,以便在视口缩小时为内容保持合理的空间。

现在我们可以再次利用网格的使用,回到我们的header 规则,添加一个对齐属性:

header {
  // ...existing styles
  align-items: center;
}

这将使内容与图像垂直对齐。由于图像被设置为header 高度的100%,从视觉上看,这将使内容垂直居中,从而形成我们的桌面英雄。

marketing hero desktop finalized

为了使其在最小的屏幕上继续工作,我们需要做一些调整。

首先,我们将默认图像宽度为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 ,但这并不太痛苦!😊

这是最后的移动尺寸视口结果:

marketing hero mobile finalized

英雄#1#中的技术总结

  • object-fit 用来控制 的大小img
  • align-items: center 用来垂直对齐网格中的儿童

英雄#2背景图片上的文本叠加#

preview of text overlay hero

在这个版本的基础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;
}

这是目前的结果:

progress of hero #2

很明显,文字的对比度在背景图片上是不够的。一个常见的方法是在图像上应用彩色屏幕,这样既可以增加品牌效应,又可以帮助解决对比度问题。

下面是我们为实现这一目标而做的小改动--首先,header ,其中包括阿尔法透明的background-color

$primary: #3c87b3;

header {
  // ...existing styles
  background-color: rgba($primary, 0.7);
}

然后,我们用z-index 来引导图片滑到标题后面。在我的测试中,这仍然可以使img 被辅助技术发现,但如果你知道有这样的问题,请联系我们:

img {
  // ...existing styles
  z-index: -1;
}

结果如下:

base of hero two completed

为了更多地展示使用网格的可能性,让我们在: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 的定义,结果就在这里了。

hero with pseudo-elements added

第一个要解决的问题是溢出问题,我们将用这个问题来解决:

header {
  // ...existing styles
  overflow: hidden;
}

接下来,网格提供了self 属性来指导那个特定的项目可以重新定位,这就把它从网格父定义中打破了。所以我们将相应地更新我们的伪元素:

&::before {
  // ...existing styles
  place-self: start;
}

&::after {
  // ...existing styles
  place-self: end;
}

就这样,我们已经完成了英雄2!测试一下演示,看看小视口版本是否继续良好地工作。

completed hero #2

英雄2#中的技术总结

  • 通过用rgba 来定义headerbackground-color ,并在img 上添加z-index: -1 ,在img 上创建了一个彩色屏幕,将其滑到后面。header
  • 使用伪元素来增加设计的亮点,并将它们与父网格定义分开,用place-self

英雄#3带副本和表格的两栏式

preview of two-column hero

在第三个例子中,我们的基础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 ,表单样式已经完好无损(破坏者:这也是在使用网格!),溢出也已经被控制了。

starting hero #3 appearance

让我们开始解决这个问题,开始我们的.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

hero #3 with grid-template-columns applied

让我们来谈谈底部的渐变边框--它是如何被定位的?

它是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 提供水平对齐。

completed large viewport appearance for hero #3

在较小的视口上,我们唯一的调整是确保内容在SVG图案上保持可读性。我们将使用与英雄#1类似的技术。

.hero__wrapper {  // ...existing styles  z-index: 1;}.hero__content {  background-color: rgba(scale-color($primary, $lightness: 90%), 0.8);  border-radius: 8px;}

hero #3 with mobile adjusted styles

英雄3#中的技术总结

  • 使用包装器为内容与header 设计元素提供一个二级网格布局。
  • 创建具有自动宽度的列grid-template-columns
  • 利用vmin ,在较小的视口上最小化填充,在较大的视口上增加填充。