UnoCSS 响应式设计和色彩主题切换 | 青年营
UnoCSS的响应式设计和颜色主题切换
UnoCSS 是一个 ????火热的原子级 CSS 引擎。具体介绍这里不多说,今天的主题是实践,概念性的知识推荐各位看官去其官方网站详细了解:
???? UnoCSS 中文文档
此外,本篇文章撸出来的小页面在线展示链接如下,对最终效果感兴趣的话可以先去看看:
???? Online Demo
准备
我使用了 React & UnoCSS 的组合(我的 Vue 比较菜 ????)。
先撸个简单的 Demo 页面,用于展示本篇的主题:
实际上就是一个简单的信息卡片,卡片底部是一个用于切换颜色主题的 checkbox。
响应式设计
历史
在 Web 发展的洪荒年代,大家搭建的网页多是使用固定布局,如果用户使用的屏幕尺寸比设计者考虑的屏幕尺寸不同,就会出现多余的滚动条或者多余的页面空白,严重降低了 ????????用户体验。
如果你想感受一下早期的 Web 前端页面,可以看看这个????历史悠久的网站,并尝试分别使用不同设备访问它(或者使用 DevTools 自带的工具)。
这个网站本身也比较有趣,以后我可能会讲讲它。
随着科技的发展,人们使用的屏幕尺寸越来越多,逐渐出现了响应式网页设计的概念(responsive web design,RWD)。RWD 是一种让网页能够根据不同的设备和屏幕尺寸自动适应的设计方法。它可以让网页在 ????手机、????电脑等设备上都能保持良好的布局和用户体验。你现在能看到的大多数网站都使用了响应式设计,最常见的就是顶部导航栏的标签:
相关概念
在正式开始之前,有一些 ????常见概念需要你了解:
-
视口(viewport)
视口是浏览器窗口中显示网页内容的区域。不同的设备有不同的视口大小,你可以使用meta标签来设置视口的宽度和缩放比例。
-
媒体查询(media query)
媒体查询是一种CSS技术,可以让你根据不同的媒体类型和特征(如屏幕宽度、高度、分辨率等)来应用不同的样式规则。
-
流式布局(fluid layout)
流式布局是一种使用百分比或相对单位(如em、rem、vw、vh等)来定义网页元素宽度和高度的布局方法。它可以让网页元素随着视口大小的变化而自动调整。
-
断点(breakpoint)
断点是指在不同的视口大小下,网页布局发生变化的临界点。你可以使用媒体查询来定义不同的断点,并在每个断点下应用不同的样式规则。
-
弹性盒子(flexbox)
弹性盒子是一种CSS布局模块,可以让你轻松地对齐和分配网页元素。它可以让你在水平或垂直方向上创建弹性的网格系统,并根据视口大小自动调整元素的大小和顺序。
-
网格(grid)
网格是另一种CSS布局模块,可以让你创建复杂的二维网格系统,并在每个网格单元中放置网页元素。它可以让你定义不同的行和列,并根据视口大小自动调整它们的大小和位置。
颜色主题
这个无需多言,很多网站都已经配置了亮色主题和暗色主题,用户可以自行选择。
实战
响应式设计
UnoCSS 基本兼容了 TailwindCSS 的语法,我们可以使用类似的方法使用断点,编写在不同尺寸下的组件样式。
首先,我们可以在配置文件中手动设置不同层级的断点。当然,你也可以使用默认值,我这里稍微做了些修改,添加了 xxs
、xxl
断点:
// uno.config.js
export default defineConfig({
... ...
theme: {
breakpoints: {
xxs: '0px',
xs: '320px',
sm: '480px',
md: '768px',
lg: '1024px',
xl: '1280px',
xxl: '1600px',
},
},
... ...
})
按照如上代码进行配置后,我们可以在 React 的 .jsx
文件中通过 md:
语法设置不同断点下的样式:
<div className={`shadow card-base text-base flex flex-col p-10 md:w-fit md:h-fit xxs:box-border xxs:items-center xxs:justify-center xxs:w-full xxs:h-full`}>
<h2 className="text-lg font-bold m-0">
Responsive Design & Theme
</h2>
<p className="mb-4 text-center">
Change window size or click the following button.
</p>
<div className='h-30px w-full flex items-center justify-center'>
<SwitchButton
height='50px'
width='60px'
layout='translate-x-[-50%]'
isChecked={isChecked}
SwitchFunction={handleSwitch}
/>
</div>
</div>
正如本篇文章开头展示的图片,这段代码实现了一个简单的信息卡片。当页面宽度不小于 768px
时,卡片为固定尺寸,可以显示背景背景;当页面宽度小于 768px
时,这个卡片会占满全屏,遮挡住页面背景。
主题切换
在这个展示页面中,我只做了一个 ????简单的亮暗色主题。
如果你想要在 UnoCSS 中使用亮暗色主题,需要在配置文件中进行设置。我使用的方法参考了该框架作者 Anthony Fu
的一条推文。
该条推文至今已有一年时间,已经出现了更加优秀的主题切换方案????。
首先,我们需要在配置文件中进行配置,设置 shortcuts
并设置了亮暗色主题的不同颜色。
export default defineConfig({
... ...
shortcuts:{
'switch-animation': 'transition duration-300',
'bg-base': 'bg-[#f0f0f0] dark:bg-[#20202a] switch-animation',
'card-base': 'bg-[#ffffff] dark:bg-[#10101a] switch-animation',
'text-base': 'text-[#20202a] dark:text-[#f0f0f0] switch-animation',
'switch-label-base': 'bg-gray-200 dark:bg-gray-800 switch-animation',
'switch-span-base': 'bg-white dark:bg-gray-300 switch-animation',
},
... ...
})
然后,我们编写一个 ????SwitchButton 组件,用于切换主题状态。为了使这个状态能够应用到主页面,我们将这个 theme
状态 ⬆提升到其父组件中,并将其值绑定到相对底层的 div 元素中,以控制颜色主题。具体代码实现如下:
// SwitchButton/index.jsx
import PropTypes from 'prop-types';
function SwitchButton({ height, width, layout, theme, SwitchFunction }) {
const handleSwitch = (event) => {
SwitchFunction(event.target.checked);
};
return (
<div className={`relative h-[${height}] w-[${width}] flex items-center justify-center ${layout}`}>
<input
type="checkbox"
id="dark-light"
className="absolute z-1 w-12 h-5"
onChange={handleSwitch}
/>
<label
htmlFor="dark-light"
className='absolute z-2 block w-11 h-6 switch-label-base rounded-full shadow-inner cursor-pointer switch-animation hover:cursor-pointer'
>
<span
className={`absolute top-1 left-1.5 w-4 h-4 switch-span-base rounded-full shadow-md switch-animation ${theme=='dark' ? 'translate-x-[100%]' : ''}`}
>
</span>
</label>
</div>
);
}
SwitchButton.propTypes = {
height: PropTypes.string.isRequired,
width: PropTypes.string.isRequired,
layout: PropTypes.string.isRequired,
theme: PropTypes.string.isRequired,
SwitchFunction: PropTypes.func.isRequired,
};
export default SwitchButton;
// App.jsx
import { useState } from 'react';
import SwitchButton from './SwitchButton/index';
function App() {
const [theme, setTheme] = useState('dark');
const handleSwitch = () => {
setTheme((prevChecked) => (prevChecked === 'dark' ? 'light' : 'dark'));
};
return (
<div className={`w-100vw h-100vh flex flex-col ${theme}`}>
<main className="w-100vw flex-1 flex justify-center items-center bg-base">
<div className={` shadow card-base text-base flex flex-col p-10 md:w-fit md:h-fit xxs:box-border xxs:items-center xxs:justify-center xxs:w-full xxs:h-full`}>
<h2 className="text-lg font-bold m-0">
Responsive Design & Theme
</h2>
<p className="mb-4 text-center">
Change window size or click the following button.
</p>
<div className='h-30px w-full flex items-center justify-center'>
<SwitchButton
height='50px'
width='60px'
layout='translate-x-[-50%]'
theme={theme}
SwitchFunction={handleSwitch}
/>
</div>
</div>
</main>
</div>
);
}
export default App;
至此,我们的颜色主题切换效果也已经实现了,具体效果如下:
-
亮色主题
-
暗色主题
后言
有一个好消息和一个坏消息。
坏消息是,这篇文章其实写得很赶 ????,要赶青训营的笔记 DDL。
好消息是,本篇文章还会在我的个人博客上继续更新 ????!文章结构和知识完整度都需要提高,随着我对 UnoCSS 的逐步学习,我会掌握更优雅的语法,然后更新这篇文章。