学习 CSS

许多刚接触网页开发的开发者都听说过关于 CSS 的恐怖故事,他们可能希望 Kobweb 通过利用 Kotlin 和类似 Jetpack Compose 的 API,就意味着他们不需要学习 CSS。

值得澄清的是:CSS 是不可避免的!

话虽如此,CSS 的名声可能比实际糟糕得多。它的许多特性实际上相当简单直观,有些还非常强大。例如,你可以高效地声明你的元素应该有一个细边框,圆角,在下方投射阴影以营造深度感,使用渐变效果作为背景,并添加一个摆动的动画效果。

我们希望,当你通过 Kobweb 学习了一些 CSS 之后,你会发现自己实际上会享受它(至少有时候是这样)!

Kobweb 如何帮助处理 CSS

Kobweb 提供了足够的抽象层,让你可以更加渐进地学习 CSS。

首先也是最重要的是,Kobweb 为你提供了一个 Kotlin 风格的类型安全的 CSS 属性 API。这比在文本文件中编写 CSS(在运行时静默失败)要好得多。

其次,像 Box、Column 和 Row 这样的布局组件可以让你在尚未理解"弹性布局"是什么之前就能快速构建丰富、复杂的布局。

同时,使用 CssStyle 可以帮助你将 CSS 分解成更小、更易管理的部分,这些部分与实际使用它们的代码紧密相关,使你的项目避免出现庞大的单一 CSS 文件。(这种庞大的 CSS 文件是 CSS 给人留下令人生畏印象的原因之一)。

例如,一个可能看起来像这样的 CSS 文件:

/* Dozens of rules... */

.important {
  background-color: red;
  font-weight: bold;
}

.important:hover {
  background-color: pink;
}

/* Dozens of other rules... */

.post-title {
    font-size: 24px;
}

/* A dozen more more rules... */

可以在 Kobweb 中转变为:

val ImportantStyle = CssStyle {
  base {
    Modifier.backgroundColor(Colors.Red).fontWeight(FontWeight.Bold)
  }

  hover {
    Modifier.backgroundColor(Colors.Pink)
  }
}
components/widgets/CriticalInformation.kt
val PostTitleStyle = CssStyle.base { Modifier.fontSize(24.px) }
components/sections/Post.kt

此外,Silk 提供了一个 Deferred 组件,它允许你声明在 DOM 完成渲染之前不会被渲染的代码,这意味着它将显示在其他所有内容之上。这是一种避免设置 CSS z-index 值的简洁方式(CSS 的另一个名声不佳的方面)。

最后,Silk 旨在提供适用于多数网站的默认样式组件。这意味着你应该能够在不接触 CSS 更复杂方面的情况下快速开发常见的 UI。

一个具体的例子

让我们通过一个在基本元素上添加 CSS 效果的例子来学习。

Tip

CSS 属性的两个最佳学习资源是 https://developer.mozilla.org 和 https://www.w3schools.com。 当你进行网络搜索时要留意这些网站。

我们将创建之前讨论的带边框、浮动、摆动效果的元素。重新阅读一下,以下是我们需要弄清楚如何实现的概念:

  • 创建边框
  • 圆角处理
  • 添加阴影
  • 添加渐变背景
  • 添加摆动动画

假设我们想在网站上创建一个引人注目的"欢迎"组件。我们可以从一个空的 box 开始,在里面放一些文字:

Box(Modifier.padding(topBottom = 5.px, leftRight = 30.px)) {
  Text("欢迎!!")
}
WELCOME!!

创建边框

接下来,搜索"CSS border"。顶部链接之一应该是:https://developer.mozilla.org/en-US/docs/Web/CSS/border

浏览文档并尝试交互示例。现在理解了边框属性后,让我们使用代码补全来发现 Kobweb 版本的 API:

Box(
  Modifier
    .padding(topBottom = 5.px, leftRight = 30.px)
+   .border(1.px, LineStyle.Solid, Colors.Black)
) {
  Text("欢迎!!")
}
WELCOME!!

圆角处理

搜索"CSS rounded corners"。事实证明,这里的 CSS 属性叫做"border radius":https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius

Box(
  Modifier
    .padding(topBottom = 5.px, leftRight = 30.px)
    .border(1.px, LineStyle.Solid, Colors.Black)
+   .borderRadius(5.px)
) {
  Text("欢迎!!")
}
WELCOME!!

添加阴影

搜索"CSS shadow"。有几种类型的 CSS 阴影特性,但经过快速阅读,我们意识到我们想使用 box shadows:https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow

在尝试了模糊和扩展值后,我们得到了看起来不错的效果:

Box(
  Modifier
    .padding(topBottom = 5.px, leftRight = 30.px)
    .border(1.px, LineStyle.Solid, Colors.Black)
    .borderRadius(5.px)
+   .boxShadow(blurRadius = 5.px, spreadRadius = 3.px, color = Colors.DarkGray)
) {
  Text("欢迎!!")
}
WELCOME!!

添加渐变背景

搜索"CSS gradient background"。这不像前面的例子那样是一个简单的 CSS 属性,所以我们得到的是一个更通用的文档页面,解释了这个特性:https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_images/Using_CSS_gradients

这个例子最终找到 Kotlin 类型安全等价物有点棘手,但如果你深入研究 CSS 文档,你会发现线性渐变是一种背景图像。

Box(
  Modifier
    .padding(topBottom = 5.px, leftRight = 30.px)
    .border(1.px, LineStyle.Solid, Colors.Black)
    .borderRadius(5.px)
    .boxShadow(blurRadius = 5.px, spreadRadius = 3.px, color = Colors.DarkGray)
+   .backgroundImage(
+       linearGradient(
+          LinearGradient.Direction.ToRight, Colors.LightBlue, Colors.LightGreen
+       )
+    )
) {
  Text("欢迎!!")
}
WELCOME!!

添加摆动动画

最后,搜索"CSS animations":https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations

你可以查看 animation section 以了解 Kobweb 如何支持这个特性,这需要声明一个顶级的 Keyframes 块,然后在动画修饰符中引用它:

// Top level property
+val WobbleKeyframes = Keyframes {
+  from { Modifier.rotate((-5).deg) }
+  to { Modifier.rotate(5.deg) }
+}

// 在你的 @Page 组合函数中
Box(
  Modifier
    .padding(topBottom = 5.px, leftRight = 30.px)
    .border(1.px, LineStyle.Solid, Colors.Black)
    .borderRadius(5.px)
    .boxShadow(blurRadius = 5.px, spreadRadius = 3.px, color = Colors.DarkGray)
    .backgroundImage(linearGradient(LinearGradient.Direction.ToRight, Colors.LightBlue, Colors.LightGreen))
+   .animation(
+     WobbleKeyframes.toAnimation(
+       duration = 1.s,
+       iterationCount = AnimationIterationCount.Infinite,
+       timingFunction = AnimationTimingFunction.EaseInOut,
+       direction = AnimationDirection.Alternate,
+     )
    )
) {
  Text("欢迎!!")
}
WELCOME!!

完成了!

上面的元素不会赢得任何风格奖项,但我希望这能展示出 CSS 在几行声明性代码中能给你带来多大的力量。感谢 CSS 的特性,加上 Kobweb 的实时重载体验,我们能够逐步尝试我们的想法。

CSS 2 Kobweb

我们的主要项目贡献者之一创建了一个名为 CSS 2 Kobweb 的网站,旨在简化将 CSS 示例转换为等效的 Kobweb CssStyle 和/或 Modifier 声明的过程。

CSS 2 Kobweb example

Tip

CSS 2 Kobweb 还支持指定类名选择器和关键帧。 例如,看看当你粘贴以下 CSS 代码时会发生什么:

.site-banner {
  position: relative;
  padding-left: 10px;
  padding-top: 5%;
  animation: slide-in 3s linear 1s infinite;
  background-position: bottom 10px right;
  background-image: linear-gradient(to bottom, #eeeeee, white 25px);
}
.site-banner:hover {
  color: rgb(40, 40, 40);
}
@keyframes slide-in {
  from {
    transform: translateX(-2rem) scale(0.5);
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

网络上充满了有趣的 CSS 效果示例。几乎任何与 CSS 相关的搜索都会产生大量的 StackOverflow 答案、带有所见即所得编辑器的交互式游乐场和博客文章。许多这些介绍了一些非常新颖的 CSS 示例。这是学习更多关于网页开发的好方法!

然而,正如前一节所示,从 CSS 示例到等效的 Kobweb 代码有时可能会很麻烦。我们希望 CSS 2 Kobweb 能够帮助解决这个问题。

这个项目已经非常有用,但仍处于早期阶段。如果你发现 CSS 2 Kobweb 的某些情况不正确,请考虑在他们的仓库中 提交问题。