在本教程中,我们将构建另一个有吸引力的静态投资组合页面,这一次以纯 css 条形图为特色,不使用任何外部 javascript 库、svg 或canvas元素!
我们正在建造什么
这是我们将要创建的项目:
See the Pen A Simple, Static Portfolio Page by Envato Tuts+ (@tutsplus) on CodePen.
我们有很多令人高兴的事情要介绍,所以让我们开始吧!
注意:本教程假设 有一些 良好的 CSS 知识。例如,您应该熟悉 CSS 定位和 flexbox 基础知识。
1. 从页面标记开始
页面标记由标题和三个全屏部分组成:
<header class="position-fixed text-lightblue page-header">...</header>
<section class="d-flex justify-content-center align-items-center vh-100">...</section>
<section class="d-flex vh-100 bg-lightwhite">...</section>
<section class="d-flex flex-column justify-content-center align-items-center vh-100 position-relative">...</section>
注意:除了元素的特定类之外,我们的标记还包含许多实用程序(帮助程序)类。我们将使用这种方法来保持我们的 CSS 尽可能 DRY 。但是,为了便于阅读,在 CSS 中我们不会对常见的 CSS 规则进行分组。
2. 定义一些基本样式
按照我们上面刚刚讨论的内容,我们首先指定一些重置规则以及一些帮助类:
:root {
--gray: #cbcfd3;
--white: white;
--black: #1a1a1a;
--lightwhite: whitesmoke;
--lightblue: #009dd3;
--peach: #ff9469;
--transition-delay: 0.3s;
--transition-delay-step: 0.3s;
--skills-width: 120px;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
a {
text-decoration: none;
color: inherit;
}
.d-block {
display: block;
}
.d-flex {
display: flex;
}
.flex-column {
flex-direction: column;
}
.justify-content-center {
justify-content: center;
}
.justify-content-between {
justify-content: space-between;
}
.align-items-center {
align-items: center;
}
.align-items-end {
align-items: flex-end;
}
.flex-grow-1 {
flex-grow: 1;
}
.vh-100 {
height: 100vh;
}
.position-relative {
position: relative;
}
.position-absolute {
position: absolute;
}
.position-fixed {
position: fixed;
}
.text-center {
text-align: center;
}
.text-gray {
color: var(--gray);
}
.text-lightblue {
color: var(--lightblue);
}
.text-peach {
color: var(--peach);
}
.bg-white {
background: var(--white);
}
.bg-lightwhite {
background: var(--lightwhite);
}
.h1 {
font-size: 2.5rem;
}
.h2 {
font-size: 2rem;
}
我们的帮助类的命名约定受到 Bootstrap 4 的类名的启发。
3.构建页眉
页眉包括:
标志
主导航
<header class="position-fixed bg-white page-header">
<nav class="d-flex justify-content-between align-items-center">
<a href="" class="text-peach logo">
<strong>DM</strong>
</a>
<ul class="d-flex">
<li>
<a href="#skills">Skills</a>
</li>
<li>
<a href="#contact">Contact</a>
</li>
</ul>
</nav>
</header>
标题 CSS
.page-header {
left: 0;
right: 0;
top: 0;
padding: 20px;
z-index: 10;
}
.page-header .logo {
font-size: 1.7rem;
}
.page-header li:not(:last-child) {
margin-right: 20px;
}
.page-header a {
font-size: 1.1rem;
}
4. 建立英雄部分
我们页面的第一部分包括:
一个标题
号召性用语
这是它的样子:
第 #1 节 HTML
<section class="d-flex justify-content-center align-items-center vh-100">
<h1 class="text-center h1">...</h1>
<div class="position-absolute scroll-down">...</div>
</section>
第 1 节 CSS
号召性用语包括一条无限动画的细线,迫使用户向下滚动以查看“折叠”下方的内容(可能存在也可能不存在)。
它的风格:
.scroll-down {
left: 50%;
bottom: 0;
transform: translateX(-50%);
text-transform: uppercase;
transition: all 0.5s;
}
.scroll-down.is-hidden {
opacity: 0;
visibility: hidden;
}
.scroll-down::after {
content: '';
display: block;
margin: 3px auto 0;
width: 1px;
height: 60px;
background: var(--black);
transform-origin: bottom;
animation: pulse 3.5s infinite linear;
}
@keyframes pulse {
0% {
transform: scaleY(1);
}
50% {
transform: scaleY(0.65);
}
100% {
transform: scaleY(1);
}
}
第 1 节 JavaScript
最初,号召性用语将是可见的。但是当用户开始滚动时,它就会消失。更具体地说,它将接收is-hidden我们刚刚在上述样式中定义的类。
这是所需的 javaScript 代码:
const scrollDown = document.queryselector(".scroll-down");
window.addeventListener("scroll", scrollHandler);
function scrollHandler() {
window.pageYOffset > 0
? scrollDown.classList.add("is-hidden")
: scrollDown.classList.remove("is-hidden");
}
5. 构建第 2 部分
我们页面的第二部分包括:
背景图像
展示网络技能的条形图
这是它的样子:
第 #2 节 HTML
<section class="d-flex vh-100 bg-lightwhite" id="skills">
<div class="position-relative flex-grow-1 bg-img"></div>
<div class="d-flex justify-content-center align-items-center flex-grow-1">
<div class="position-relative chart-wrapper">
<ul class="d-flex flex-column chart-skills">
<li class="position-relative">
<span>CSS</span>
</li>
...
</ul>
<ul class="d-flex position-absolute chart-levels">
<li class="flex-grow-1 position-relative">
<span class="position-absolute">Novice</span>
</li>
...
</ul>
</div>
</div>
</section>
为背景图像设置样式
本节的左侧包含从Envato Elements 上的wordpress 代码背景获取的图像。它将为我们提供我们正在寻找的氛围,同时激发我们在设计中其他地方使用的颜色:
一些关键的事情:
图像将出现在宽于 900 像素的屏幕上,并且
我们将使用 CSS(通过background-image属性)而不是 HTML(通过img元素)将图像放置在页面中。我们选择这种方法是因为它为我们提供了一种增强图像外观的简单方法。例如,我们将利用它的 ::after伪元素来扭曲它。例如,您甚至可以使用它来玩弄它的颜色 background-blend-mode: luminosity。
注意:默认情况下 animg是一个空元素并且没有伪元素。
对应的样式:
.bg-img {
background: #fff url(bg-programming.jpg) no-repeat center / cover;
}
.bg-img::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 7rem;
background: var(--lightwhite);
transform: skew(-5deg);
transform-origin: left bottom;
}
@media screen and (max-width: 900px) {
.bg-img {
display: none;
}
}
设置图表样式
在这一点上,我们将专注于演示中最具挑战性的部分;如何构建条形图。
该图表将有两个轴。在 y 轴上,我们将放置网络技能(CSS、HTML、JavaScript、python、Ruby)。在另一个 x 轴上,我们将放置技能级别(新手、初学者、中级、高级、专家)。
y 轴
在标记方面,每个技能都是放置在列表中的列表项.chart-skills。接下来,每个列表项将在一个span元素中保存其文本,如下所示:
<ul class="chart-skills">
<li class="position-relative">
<span>CSS</span>
</li>
...
</ul>
我们为元素定义了一个固定宽度,span等于 120px。为了避免重复,我们可以很容易地改变这个值(因为其他值会依赖它),让我们将它存储在一个 CSS 变量中:
:root {
--skills-width: 120px;
}
.chart-wrapper .chart-skills span {
display: inline-block;
width: var(--skills-width);
padding: 15px;
}
每个列表项都将包含它自己的::before伪::after元素:
/*CUSTOM VARIABLES HERE*/
.chart-wrapper .chart-skills li::before,
.chart-wrapper .chart-skills li::after {
content: '';
position: absolute;
top: 25%;
left: var(--skills-width);
height: 50%;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
z-index: 2;
}
伪元素将::after具有浅灰色和静态宽度,该宽度是通过span从列表项宽度中减去宽度来计算的:
.chart-wrapper .chart-skills li::after {
width: calc(100% - var(--skills-width));
background: rgba(211, 211, 211, 0.3);
}
这是它的外观:
::before所有伪元素的初始宽度将为 0:
/*CUSTOM VARIABLES HERE*/
.chart-wrapper .chart-skills li::before {
width: 0;
background: var(--lightblue);
transition: width 0.65s ease-out;
}
但是一旦图表在视口中可见,它们的宽度就会被动画化并接收一个由相关技能水平决定的值:
在视图中添加类
有多种方法可以检测元素在视口中是否可见。让我们利用从一个古老但流行的StackOverflow 线程中提取的以下便捷函数:
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
所以,回到手头的工作!当图表在当前视口中可见时,我们将给它in-view类。
这是完成这项工作的 JavaScript 代码:
const chartWrapper = document.querySelector(".chart-wrapper");
window.addEventListener("scroll", scrollHandler);
function scrollHandler() {
if (isElementInViewport(chartWrapper)) chartWrapper.classList.add("in-view");
}
::before伪元素应按顺序设置动画。为了给它们所需的过渡速度,我们将使用另外两个 CSS 变量以及 calc() CSS 函数。
以下是负责显示这些 sudo 元素的 CSS 样式:
:root {
...
--transition-delay: 0.3s;
--transition-delay-step: 0.3s;
--skills-width: 120px;
}
.chart-wrapper.in-view .chart-skills li:nth-child(1)::before {
width: calc(90% - var(--skills-width));
transition-delay: var(--transition-delay);
}
.chart-wrapper.in-view .chart-skills li:nth-child(2)::before {
width: calc(75% - var(--skills-width));
transition-delay: calc(
var(--transition-delay) + var(--transition-delay-step)
);
}
.chart-wrapper.in-view .chart-skills li:nth-child(3)::before {
width: calc(62% - var(--skills-width));
transition-delay: calc(
var(--transition-delay) + var(--transition-delay-step) * 2
);
}
.chart-wrapper.in-view .chart-skills li:nth-child(4)::before {
width: calc(49% - var(--skills-width));
transition-delay: calc(
var(--transition-delay) + var(--transition-delay-step) * 3
);
}
.chart-wrapper.in-view .chart-skills li:nth-child(5)::before {
width: calc(38% - var(--skills-width));
transition-delay: calc(
var(--transition-delay) + var(--transition-delay-step) * 4
);
}
请记住,Microsoft Edge 不支持上述数学运算,因此如果您需要支持它,只需传递一些静态值即可,如下所示:
.chart-wrapper.in-view .chart-skills li:nth-child(2)::before {
transition-delay: 0.6s;
}
.chart-wrapper.in-view .chart-skills li:nth-child(3)::before {
transition-delay: 0.9s;
}
x 轴
在标记方面,每个级别都是放置在列表中的列表项 .chart-levels 。接下来,每个列表项将在一个 span 元素中保存其文本,如下所示:
<ul class="d-flex position-absolute chart-levels">
<li class="flex-grow-1 position-relative">
<span class="position-absolute">Novice</span>
</li>
...
</ul>
需要注意的一些事项:
我们将列表设置为弹性容器。此外,我们绝对定位它并给它一个等于span第一个列表的 s 宽度的左填充。
我们提供列表项 flex-grow: 1 以增长并占用所有可用空间。
s 位于其父列表项的 span最底部。
该列表的关联样式:
/*CUSTOM VARIABLES HERE*/
.chart-wrapper .chart-levels {
left: 0;
bottom: 0;
width: 100%;
height: 100%;
padding-left: var(--skills-width);
}
.chart-wrapper .chart-levels li {
border-right: 1px solid rgba(211, 211, 211, 0.3);
}
.chart-wrapper .chart-levels li:last-child {
border-right: 0;
}
.chart-wrapper .chart-levels span {
bottom: 0;
transform: translateY(50px) rotate(45deg);
padding: 10px;
width: 100%;
}
6. 构建第 3 部分
我们页面的第三部分包括:
一个标题
一个mailto链接
这是它的样子:
第 3 节 HTML
<section class="d-flex flex-column justify-content-center align-items-center vh-100 position-relative" id="contact">
<h2 class="h1">...</h2>
<a href="mailto:hello@digitalmonsters.com" class="text-gray h2">...</a>
</section>
7. 响应迅速
我们快完成了!最后一件事,让我们确保文本在所有屏幕上都具有清晰的外观。我们将应用针对窄屏的规则:
@media screen and (max-width: 600px) {
html {
font-size: 12px;
}
}
这里的一个重要注意事项是,在我们的样式中,我们用于 rem 设置字体大小。这种方法非常有用,因为字体大小是相对于根元素 ( html) 的。如果我们像上面的代码那样减小它的字体大小,与 rem 相关的字体大小将动态减小。当然,我们也可以将rems 用于其他 CSS 属性。
我们项目的最终状态:
See the Pen A Simple, Static Portfolio Page by Envato Tuts+ (@tutsplus) on CodePen.
结论
在本教程中,我们通过学习如何构建一个有吸引力的静态投资组合页面来提高我们的 CSS 知识。我们更进一步,在不使用任何外部 JavaScript 库、SVG 或 canvas 元素的情况下创建了一个响应式条形图。只需使用纯 CSS!
- 我们正在建造什么
- 标题 html
- 标题 CSS
- 第 #1 节 HTML
- 第 1 节 CSS
- 第 1 节 JavaScript
- 第 #2 节 HTML
- 为背景图像设置样式
- 设置图表样式
- y 轴
- 在视图中添加类
- x 轴
- 第 3 节 HTML