Tailwind教程之7 - 定义自己的UI组件


由于Tailwind不像MUI,Bootstrap等框架一样有自己的UI组件库。因此在项目开发的时候,经常需要自己根据基本的Tailwind类来定义一个组件库,比如按钮,Card等等。

卡片组件

定义卡片

如果要定义一个卡片,需要考虑以下因素:

  • 圆角:使用rounded类,如果想要更改圆角半径,可以使用其他相关类,比如:round-full
  • div容器和图片的覆盖:如果外层div设置为圆角,但图片未设置圆角,默认情况下图片的方角将会覆盖外层div的圆角,因此可以在外层div上应用overflow-hidden类
  • 添加阴影,可以使用shadow类
  • 宽度:可以进行自适应设置,比如w-80 sm:w-96
  • object-cover: 当屏幕尺寸发生变化时,图片比例不会被拉伸,而是会zoom in/out
  • 设置圆角标题div块定位在屏幕左上角:可以在外层div设置relative定位,内层设为absolute定位

最终代码:

markup
<div class="rounded-lg overflow-hidden shadow-lg w-80 sm:w-96 relative">
  <img src="images/marguerite.jpg" alt="Marguerite" class="w-full h-32 sm:h-48 object-cover"/>
  <div>
    <span class="font-bold">Rare flower desc</span>
    <span class="block text-gray-500 text-sm">Origin: xxx</span>
  </div>
  <div class="font-bold rounded-full p-3 top-1 ml-1 mt-1 absolute">
    <span>£4.99</span>
  </div>
</div>

使用@apply

目前的做法有些问题。当我们需要多次使用卡片时,所有的样式定义都需要重复,这就不便于后续维护。为了解决这个问题,可以使用@apply来应用所有对应样式。

css
.card {
  @apply rounded-lg overflow-hidden shadow-lg w-80 sm:w-96 relative;
}

.card-title {
  @apply font-bold rounded-full p-3 top-1 ml-1 mt-1 absolute
}

.card-desc {
  @apply block text-gray-500 text-sm
}

那么在后面的div中只需要引用card, card-title, card-desc三个类就可以了。

其他类似的方法

在Tailwind中,还可以使用@screen来针对不同尺寸屏幕应用样式:

css
@screen sm {
  .btn {
    @apply inline-block px-5 py-2 rounded-lg
  }
}

注意事项

在使用自定义样式的时后,这些样式和@tailwind utilities的次序是很重要的。应该这样做:

css
@tailwind base;
@tailwind components;
/* 自定义样式 */
.card {
  @apply rounded-lg overflow-hidden shadow-lg w-80 sm:w-96 relative;
}
// ...
@tailwind utilities;

尽量不要把”@tailwind utilities;”放在自定义样式的前面。原因在于:如果使用了.card类的话,同时又想使用一些行内样式:

  • 如果”@tailwind utilities;”在自定义样式后面,行内样式会覆盖.card所定义的样式。(期待的行为)
  • 如果自定义样式在后面,则会覆盖行内样式(不期待的行为)。

关于设计的几个考虑

antialiased

为了在高清显示器上出现最好效果,在顶级元素上使用antialiased。

markup
<div id="root" class="antialiased">

</div>  

关于颜色

不建议使用黑色,而使用text-gray-900,这样看起来更加自然。

关于字体

font-bold显得有些过于突兀,可以考虑是用font-semibold

作为卡片title,可以考虑使用text-lg / text-xl

对于卡片正文部分:

  • 颜色的话,可以考虑相对较淡的颜色,比如:text-gray-700(默认为text-gray-900)
  • 字体大小:可以考虑text-sm或者text-xs uppercase font-semibold tracking-wides组合

如果正文部分有多行的话,可以考虑标题的位置,比如:

markup
<div>正文第一行</div>
<h4>标题</h4>
<div>正文第二行</div>
<div>正文第三行</div>
<div>正文第四行</div>

关于行间距

一般情况下,行间距肯定要小于padding。

如果需要,可以调整行间距:

  • leading-tight
  • leading-snug

如果标题过长,也可以使用truncate类来截断对应的文本:

  • truncate

最终示例

markup
<div class="bg-white border rounded overflow-hidden">
  <img />
  <div class="p-5">
    <div class="text-gray-600 text-xs uppercase font-semibold tracking-wide">
      short desc
    </div>
    <h4 class="font-semibold text-lg leading-tight truncate">
      Flow name
    </h4>
    <div class="mt-1">
      £4.99
    </div> 
    <div class="mt-4">
      <span class="text-real-500 font-semibold">
        5 stars
      </span>  
      <span class="text-gray-600 text-sm">
        / 139 reviews
      </span>  
    </div>   
  </div>  
</div>  

针对@apply样式的重用

如果需要定义一些重用性的样式,需要考虑把相同属性抽取出来单独定义:

css
.btn {
  @apply ...
}

.btn-indigo {
  @apply bg-indigo-600;
}

.btn-blue {
  // ...
}

按钮

如果要定义按钮,同样,应该把所有按钮的通用样式抽取出来,放在styles.pcss中,比如:

css
.button {
  @apply rounded py-1 px-2 text-xs cursor-pointer;
}

然后在使用按钮的时候直接使用这个类:

markup
<div class="button border-primary md:border-2">Submit</a>

也可以使用CSS的伪类:

css
.button:hover {
  ...
}

对于按钮的话,我们经常会需要类似这样的样式:

  • hover:bg-indigo-500: 当鼠标悬停时更改背景色
  • focus:outline-none
  • focus:shadow-outline
  • active:bg-indigo-600: 当单击时更改按钮样式。

只不过需要注意的是,要想使用active对应的样式,需要更改tailwind.config.js。需要注意,必须把所有需要的variant都设置好,同时其次序也不能随便更改。

JavaScript
// ...
variants: {
  backgroundColor: ['responsive','hover','focus','active']
}
// ...

我们还可以将md:和hover结合使用:

JavaScript
hover:bg-indigo-400 md:hover:bg-indigo-600

注意:hover:并不能和所有样式组合一起工作。比如,在默认情况下,hover:text-2xl不会正常工作,因为这种使用方式并不常见。如果想要这样使用的话,同样需要更改tailwind.config.js:

JavaScript
variants: {
  fontSize: ['responsive', 'hover']
}

图标

参考网站:https://heroicons.com/
SVG优化工具:https://jakearchibald.github.io/svgomg/

图标的使用非常简单,只要在上面网站单击对应的图标,就会将图标对应的SVG复制到剪贴板中。

markup
<div class="product-price">
  <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 inline" fill="none" viewBox="0 0 24 24" stroke="currentColor">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 9a2 2 0 10-4 0v5a2 2 0 01-2 2h6m-6-4h4m8 0a9 9 0 11-18 0 9 9 0 0118 0z" />
  </svg>
  <span>5.99</span>
</div>

如果想要更改图标颜色,可以去掉其fill属性,并在其class属性上添加:

markup
<div class="h-6 w-6 fill-current text-red-500">
  ...
</div>    

以Vue.js为例,如果想要添加五颗星的话,可以:

徽章

none
<div class="flex items-baseline">
  <span class="inline-block bg-gray-500 text-white text-xs px-2 rounded uppercase font-semibold tracking-wide">Breaking news</span>
  <div>
  ...
  </div>
</div>

图片

  • h-48 w-full: 通过这种方式来限定图片尺寸
  • object-cover: 保持图片缩放比例,占据所有可用空间
  • object-center: 从中央位置剪切图片,还可以有object-left/object-top/object-right/object-bottom等

需要注意:IE11不支持以上属性,可以使用背景图来解决。

markup
<div class="h-48 bg-cover bg-center" :style="{ backgroundImage: `url('${image_url}')`}">

但需要权衡一下这两种方式的优缺点:

  • 使用img标签:更好的accessibility,screen reader可以识别图片标记,但IE11不支持
  • 使用背景图片,浏览器兼容性更好,但screen reader不能识别

如果想要图片在不同浏览器尺寸下保持同样比例的话:

markup
<div class="relative pb-2/3">
  <img class="absolute h-full w-full object-cover">
</div>  

上面的pb-2/3是为了保持整个父容器的比例为一个矩形


文章作者: 逻思
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 逻思 !