阅读视图

发现新文章,点击刷新页面。

前端响应式网站编写套路

不知道你有没有和我有一样的疑问,像那种响应式的网站是怎么开发?用到了什么技术?这是一篇带你进入响应式开发的套路,看完基本上就能知道响应式网站开发套路,加上现在以组件化开发更是如虎添翼,废话不多说开始我们的开发之旅

环境

  • 前端:Next
  • Css框架:tailwindcss
  • UI框架:antd(其实也不用,在这个用到的很少,几乎没用)
  • 语言:TypeScript

前言

这次我们要开发的是个响应式官网首页只有首页部分,我们此次要模仿的是影视飓风首页主要包括头部、底部、中间部分三大块,这里只对头部和底部做讲解,首页全部的代码我已经全部上传 源码地址

在这也提醒各位不要频繁去刷别人的官网!!!!!!!!!

tailwindcss

这里简单的介绍下 【Next,antd,TS就不做介绍】,如果你用过像Bootstrap这类的UI框架应该了解

尺寸

响应式尺寸的前缀有 md lg xl等等,这些都代表对应的尺寸

前缀 尺寸
sm 640px及以上
md 768px及以上
lg 1024px及以上
xl 1280px及以上
2xl 15360px及以上

如果没有你要的尺寸或与你需要对应的尺寸有出入你也可以自己设置,tailwindcss 给开发者提供的修改的地方

import type { Config } from 'tailwindcss';

export default {
  content: [
    './pages/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}',
    './app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      screens: {
        xs: '349px', // 设置你需要的尺寸
      },
      colors: {
        background: 'var(--background)',
        foreground: 'var(--foreground)',
      },
    },
  },
  plugins: [],
} satisfies Config;

常用的class名称

  • text- fontSize
  • bg- background
  • mx- my- m- mb- ml- mr- margin
  • px- py- p- pl- pr- padding
  • w- h- width height
  • 还有其他类名在实战中再做介绍,上面一些用法也在实战中做介绍,还有一些组合用法也会在实战做介绍

tailwind CSS 规则 非常重要!!!!!

  • 非响应式类(如 hidden, flex)在所有屏幕尺寸下生效。
  • 响应式类(如 lg:flex, md:hidden)只在指定尺寸及以上生效。响应式类是以断点前缀: + 属性类
  • 优先级规则:当非响应式类与响应式类冲突时,响应式类会在其生效的屏幕尺寸范围内覆盖非响应式类

分析网页

欲先善其事,必先利其器,我先分析下页面

250607 141330.gif 通过上面的gif图我们看到网页便没有随着宽度变化而发生变化,在切换到移动模式后需要再次刷新页面才会发生变化,我们第一步需要将其改造为随着页面变化自动变化,底部导航也是一样这就不截图了

gif录制工具

头部编码与分析

image.png 头部导航主要分为三块左右布局,左边我又将其分为两块,为后面响应式做好准备,现在开始编码与分析,下面展示的都是部分代码,但不影响布局分析

<div
  className="fixed w-dvw overflow-hidden z-50 bg-white md:px-4  xs:px-2   sm:px-1.5  lg:px-20   flex justify-between items-center h-[70px]
">
 
    {/*左侧开始*/}
  <div className="flex ">
    <img className="w-[7.5rem] h-[2.25rem] mr-[70px]" src="/images/banner-login1.png" alt=""/>
    <YSJFNav isTrue={isTrue}/>
  </div>
    {/*左侧结束*/}

  {/*右侧开始*/}
  <div className=" text-gray-300">
    <svg onClick={() => setIsShow(!isShow)} className="lg:flex hidden size-6 rounded-full"
         xmlns="http://www.w3.org/2000/svg"
         fill="none" viewBox="0 0 24 24"
         strokeWidth={1.5} stroke="currentColor"
         style={{color: isTrue ? 'gray' : 'black', background: isTrue ? '#cecece' : '#f4f6f7',}}>
      <path strokeLinecap="round" strokeLinejoin="round"
            d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
    </svg>

    <svg onClick={() => setIsNav(!isNav)} className="lg:hidden size-6" xmlns="http://www.w3.org/2000/svg" fill="none"
         viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
      <path strokeLinecap="round" strokeLinejoin="round"
            d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0ZM3.75 12h.007v.008H3.75V12Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm-.375 5.25h.007v.008H3.75v-.008Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z"/>
    </svg>
  </div>
  {/*右侧结束*/}
  
</div>
<ul className="lg:flex hidden  items-center  text-[12px] transition text-[#c9c9c9]">
  <li
    className="w-[70px] mr-[60px] cursor-pointer hover:scale-110 transition hover:tracking-[2px]">影视飓风
  </li>
  <li
    className="w-[70px] mr-[60px] cursor-pointer hover:scale-110 transition hover:tracking-[2px]>飓风素材库
  </li>
  <li
    className="w-[70px] mr-[60px] cursor-pointer hover:scale-110 transition hover:tracking-[2px]>闪电分镜
  </li>
  <li
    className="w-[70px] mr-[60px] cursor-pointer hover:scale-110 transition hover:tracking-[2px]>太空之眼
  </li>
  <li
    className={isTrue ? "w-[70px]  cursor-pointer  hover:scale-110 transition hover:tracking-[2px]" : "w-[70px]  cursor-pointer  hover:scale-110 transition hover:tracking-[2px] hover:text-black"}>加入我们
  </li>
</ul>

最外层分析

  • 在最外层我们设置了fixed属性让他在页面滚动的时候一直固定在头部,设置宽度w-dvw= width: 100dvw让它宽度一直都是和设备宽度一样,同时我们加上 overflow-hidden 让超出部分直接隐藏
    • 在头部X轴我们加了响应式内边距,分别在md xs lg 对应的尺寸设置不同内边距
    • 头部导航高度我们这就直接写死一个高度h-[70px],这就是tailwindcss一个好处,不仅可以使用内置已有属性,还可以自己写需要的单位
    • flex justify-between items-center 两边居中排列

头部导航右侧分析

  • 这里用到两个图表,一个是PC像登录按钮,一个是移动端点击呼出菜单的按钮
  • 这里是需要设置响应式,在不同尺寸下显示不同的图标和事件
    • lg:felx hidde在屏幕大于等1024px显示,小于就不显示
    • lg:hidde在屏幕大于等1024px隐藏,小于显示

头部导航左侧分析

  • 使用felx布局只为了让他们在一行
  • 我们给图片添加了w-[7.5rem]``w-[2.25rem]直接将宽高写死,如果想做成响应式可以自行添加响应式
  • 右侧的导航YSJFNav.tsx
    • 这里也同样需要添加响应式,我们给ul添加响应式:lg:flex hidden在屏幕大于等1024px显示,小于就不显示,因为是在PC下显示我们就将字体大小写死,text-[#c9c9c9] 字体颜色
    • liw-[70px]就不作解释,cursor-pointer hover:scale-110 transition hover:tracking-[2px]鼠标显示成手,在移上去的时候文字放大字间距变宽
    • 到这头部布局和用到的样式就解释完毕

登录界面变化与分析

如果你看过原来官网会发现也是没有进行响应式设置,我们也是要对其进行改造,我们先看下效果

250607 160712.gif

<div className='fixed top-0 left-0 overflow-hidden w-full h-full bg-[#000000b3] text-white'>
  <div className='md:w-[50rem]  xs:w-11/12 absolute top-2/4 left-2/4 -translate-x-2/4 -translate-y-2/4 bg-white text-black '>
    <div className='p-1 flex justify-end cursor-pointer ' onClick={() => closeModal()}>
      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className=" size-6">
        <path strokeLinecap="round" strokeLinejoin="round" d="M6 18 18 6M6 6l12 12" />
      </svg>
    </div>

    <div className='flex'>

      <img className='w-96 md:flex hidden' src="images/login.jpg" />

      <div className='pt-[70px] pr-5 ml-5 w-full'>
        {/*tab*/}
        <ul className='flex text-gray-300 text-[12px] mb-3 lg:w-full relative'>
          <li className={flag ? 'mr-4 cursor-pointer' : "mr-4 cursor-pointer text-black"} onClick={() => loginOrRegister()}>密码登录</li>
          <li className={flag ? 'mr-4 cursor-pointer text-black' : "mr-4 cursor-pointer"} onClick={() => loginOrRegister()}>验证码登录</li>
        </ul>

        {/*登录注册*/}
        {flag ? <Register /> : <Login toRegister={() => loginOrRegister()} />}

        <Divider><span className='text-[12px] text-gray-400'>或</span></Divider>

        {/*微信登录*/}
        <div className='mb-5 flex justify-center  bg-white text-black rounded-md p-[10px] border-[#eee] border text-[12px] text-center'>
          <WechatFilled style={{ fontSize: 16, color: 'green' }} />
          <span className='ml-2'>微信登录</span>
        </div>

        {/*条款*/}
        <Clause />
      </div>
    </div>
  </div>
</div>

最外层分析

在底部我们加了一层遮罩同时为了脱离文档流我们用到了定位,fixed top-0 left-0 overflow-hidden w-full h-full bg-[#000000b3] text-white,固定定位 上左都是0 高度宽度100%,bg-[#000000b3]一种背景色,文字白色

表单区域分析

  • absolute top-2/4 left-2/4 -translate-x-2/4 -translate-y-2/4 居中布局
  • top-2/4 left-2/4 = top:50% left:50%
  • -translate-x-2/4 -translate-y-2/4 = translate-y:-50% translate-x:-50%
  • 如果把-translate-x-2/4前面的负号去掉translate-x-2/4 = translate-x:50%`,同理我们可以推出类似的类,如果要取负数只需要在类名前面添加负号就行
  • 同理这里也需要用到响应式:md:w-[50rem] xs:w-11/12,md是框架自带的xs是我自定义的在前面tailwindcss尺寸哪有介绍
  • 内容区域两块左右结构,在图片部分我们需要做响应式在指定尺寸下隐藏
    • md:flex hidden这里就不解释了

移动端菜单显示

好在现在的前端是以组件化进行开发,我们只需要将移动端单独编写就行了,通过点击事件显示就好了,这里主要还是用到了antdDrawer

 <Drawer width='85%' placement="right" closable={false} open={true} bodyStyle={{ padding: 0 }} >
  <div className='flex justify-between mb-4 p-[24px]'>
    <svg onClick={() => onClose('close')} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
      <path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />
    </svg>
    <div onClick={() => onClose('login')} className='bg-[#f4f6f7] rounded-[5px] font-semibold px-[11px] py-[6px] text-[#24252c] text-[12px]'>登录</div>
  </div>
  <ul className=' text-base '>
    <li className='px-[24px] font-semibold py-[24px] active:bg-[#F4F6F7]'>影视飓风</li>
    <li className='px-[24px] font-semibold py-[24px] active:bg-[#F4F6F7]'>飓风素材库</li>
    <li className='px-[24px] font-semibold py-[24px] active:bg-[#F4F6F7]'>闪电风景</li>
    <li className='px-[24px] font-semibold py-[24px] active:bg-[#F4F6F7]'>太空之眼</li>
    <li className='px-[24px] font-semibold py-[24px] active:bg-[#F4F6F7]'>加入我们</li>
  </ul>
</Drawer>

在编写头部的时候,我们在右侧留下可以点击的部分

<div className=" text-gray-300">

    {/*PC登录按钮 */} 
  <svg onClick={() => setIsShow(!isShow)} className="lg:flex hidden size-6 rounded-full"
       xmlns="http://www.w3.org/2000/svg"
       fill="none" viewBox="0 0 24 24"
       strokeWidth={1.5} stroke="currentColor"
       style={{color: isTrue ? 'gray' : 'black', background: isTrue ? '#cecece' : '#f4f6f7',}}>
    <path strokeLinecap="round" strokeLinejoin="round"
          d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
  </svg>
  
  {/*移动端呼出菜单按钮 */} 
  <svg onClick={() => setIsNav(!isNav)} className="lg:hidden size-6" xmlns="http://www.w3.org/2000/svg" fill="none"
       viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
    <path strokeLinecap="round" strokeLinejoin="round"
          d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0ZM3.75 12h.007v.008H3.75V12Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm-.375 5.25h.007v.008H3.75v-.008Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z"/>
  </svg>
</div>

底部编码与粗略分析

我们直接看修改后的响应式效果

250607 162749.gif

 <div className='w-full lg:flex justify-around hidden'>

  {listArray.length && listArray.map((item, index) => {
    return <div key={item.text} className='flex justify-center flex-col items-center mt-[40px] ' onMouseLeave={() => setIsShow(index)} onMouseEnter={() => setIsShow(index)}>
      <img className={`${item.isShow ? styles.entrance : styles.field}  w-[88px] h-[66px]`} src={item.isShow ? item.activeImg : item.img} alt="" />
      <p className={`${item.isShow ? styles['text-entrance'] : styles['text-field']} mt-[40px]`}>{item.text}</p>

      <div className={`{isShow && ${item.isShow ? styles['slogan-entrance'] : styles['slogan-field']} flex flex-col  items-center`}>
        <p className={`text-[12px]`}>{item.slogan}</p>
        <div className='flex'>
          {item.icon.map((img, index) => {
            return <img key={index} className='w-10 h-10  hover:scale-150 transition' src={img} alt="" />
          })}
        </div>
      </div>
    </div>
  })}
</div >
<div className="lg:hidden mt-12 ">

  <div className='px-4 mb-4'>
    <p className='text-sm text-[#646464 ] font-[600]'>ACCOUNT</p>
    <p className="text-[#24252C] font-[600] text-2xl">官方账号</p>
  </div>

  <ul className='px-4'>
    {
      listArray.map((item, index) => {
        return <div key={index} className='mb-6'>
          <li className=" bg-[#F4F6F7] p-4">
            <div className="flex justify-between items-center">
              <div className="flex items-center">
                <img className="w-16 h-12 mr-2" src={item.activeImg} alt=""/>
                <div>
                  <p className="text-[0.85rem] text-[#24252C] font-[600]">{item.text}</p>
                  <p className="text-[0.75rem] text-[#646464] font-[300]">{item.slogan}</p>
                </div>
              </div>
              {!item.isShow &&
                <svg onClick={() => isShow(index)} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
                     strokeWidth={1.5}
                     stroke="currentColor" className="size-6">
                  <path strokeLinecap="round" strokeLinejoin="round"
                        d="M3 4.5h14.25M3 9h9.75M3 13.5h9.75m4.5-4.5v12m0 0-3.75-3.75M17.25 21 21 17.25"/>
                </svg>}


              {item.isShow &&
                <svg onClick={() => isShow(index)} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
                     strokeWidth={1.5}
                     stroke="currentColor" className="size-6">
                  <path strokeLinecap="round" strokeLinejoin="round"
                        d="M3 4.5h14.25M3 9h9.75M3 13.5h5.25m5.25-.75L17.25 9m0 0L21 12.75M17.25 9v12"/>
                </svg>}

            </div>
          </li>

          {
            item.isShow &&
            <div className="bg-[#F4F6F7]  p-4 justify-between"
                 style={{display: 'grid', gridTemplateColumns: 'repeat(4, auto)', gap: '20px'}}>
              {item.icon.map((pItem, index) => {
                return <img key={index} src={pItem} alt=""
                            className="w-10 h-10 hover:scale-110 transition hover:tracking-[2px]"/>
              })}
            </div>
          }

        </div>
      })
    }
  </ul>
</div>

这次我们将底部分为PC和移动端两个组件编写,在两个组件之间进行,只需要在两个组件最外层的上加上lg:flexlg:hidden就能实现在不同尺寸上的显示,是不是很简单

文章只对头部和底部进行的分析,看到这你也就应该知道的响应式的开发套路,对于中间部分你应该也有思路怎么去开发

总结

  • 现在做下总结,响应式的网站就是通过给在不同尺寸下显示不同的内容和布局,但在移动下一些问题还需要特殊处理
  • 如果PC和移动端有较大出路,可以选择分为两个组件进行维护,还可以将一些相同的方法抽成一个HOOK
  • 源码地址

记住这张表

前缀 尺寸
sm 640px及以上
md 768px及以上
lg 1024px及以上
xl 1280px及以上
2xl 15360px及以上

重点记住规则 非常重要!!!!!

  • 非响应式类(如 hidden, flex)在所有屏幕尺寸下生效。
  • 响应式类(如 lg:flex, md:hidden)只在指定尺寸及以上生效。响应式类是以断点前缀: + 属性类
  • 优先级规则:当非响应式类与响应式类冲突时,响应式类会在其生效的屏幕尺寸范围内覆盖非响应式类
❌