现在是 CSS 部分。
css
复制
下载
:root{
--bg:#0d0f14;
--panel:#161a22;
--panel2:#1d222c;
--line:#262c38;
--txt:#e8edf5;
--dim:#8b95a7;
--mint:#5ce1b9;
--amber:#ffb85c;
--rose:#ff6b81;
}
字体栈是 system-ui……
先想一下 header 的部分:做成 sticky,带模糊效果。
Logo:用内联 SVG 加上文字“漫格汇”。其实 logo 也可以直接用图片?需求里说“图片和logo一起完善”—— 那 logo 也用图片来做?可以做一个内联 SVG 的 logo 标识,再加文字。不过我还是把 logo 做成内联 SVG 图形,这样更稳,不依赖外部资源。
嗯,不过“图片和logo一起完善”——也许该用 /upload/vod/ 下的图片……但 logo 命名规则又没覆盖到。所以还是用内联 SVG 做 logo 比较合适。
接下来就搭整体了。
顶部导航链接:首页、热榜、分类、新番速递、短剧漫画、资讯、留言。
接下来是 hero 区域:
html
复制
下载
运行
等等,h1 应该只出现一次,并且包含主关键词。好的。
轮播:也许可以加几个小的缩略图当指示器。保留它。
实际上我要把 hero 做成一个真正的迷你轮播,用纯 JS 自动轮换横幅图,并且带指示器圆点。挺不错的细节。
继续写。
然后是分类条:带锚点的标签 —— #hot #selection #new #shortplay #rank #news。
然后是主布局:
html
复制
下载
运行
侧边栏:热搜榜(锚点到 #hot)、推荐内链、标签云、追更日历。
嗯,侧边栏应该用 sticky 定位。
然后是全宽的 FAQ + 留言区。
评论区展示一些评论和头像。
好,现在来写 CSS。
我需要让卡片用 .card 类,包含 .card-poster img、更新角标、标题和元信息。
图片降级:用 onerror 设置一个占位背景——onerror="this.style.display='none'" 然后父元素已经有背景了。实际上更好的做法是:onerror="this.classList.add('img-fail')" 加上父元素背景渐变。更简单的方式:onerror="this.src='/upload/vod/066-banner.webp'"——但这是内联 data,允许的(不是外部资源)。嗯,可能有点乱。还是用 onerror 来设置一个 data URI 的 SVG 占位符吧。
实际上最简单的是:onerror="this.style.opacity=0",父元素的 .poster 已经有了渐变背景和 🎬 emoji 作为 ::after 内容。可以——父元素有背景。
就用这个:
css
复制
下载
.poster{position:relative;background:linear-gradient(135deg,#1d222c,#2a3140);overflow:hidden}
.poster::after{content:"📖";position:absolute;inset:0;display:grid;place-items:center;font-size:2rem;opacity:.25;z-index:0}
.poster img{position:relative;z-index:1;...}
这样,如果图片加载失败(被隐藏或直接移除),占位符就会显示出来。
用 onerror="this.remove()" 来移除图片,这样底下的占位 emoji 就能露出来了。可以。
然后是 lazy loading:加一个 loading="lazy" 属性。
现在开始写完整代码。
卡片数据用 JS 来写——每个卡片用 data 属性来承载详情内容。
我会用这种方式来组织卡片:
html
复制
下载
运行
更新至第128话
点击卡片(除了按钮之外)会打开弹窗。
追更按钮:通过 JS 切换状态——显示“已追更”。要给出反馈。
然后是弹窗的 HTML:
html
复制
下载
运行
好。
然后是 JSON-LD,包含 WebSite 和 FAQPage。
开始写内容。所有内容都用中文写。
关键词:漫画免费观看(主词),再加上长尾词:免费漫画在线阅读、国漫免费看、日漫全集免费、短剧改编漫画、热血漫画推荐、漫画大全免费、追更漫画网站、免费看漫画app……
密度保持在 2-5% 左右。主词大概出现 15-25 次。
把内容都写出来。
现在仔细写 CSS。
css
复制
下载
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth;scroll-padding-top:84px}
body{font-family:system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--txt);line-height:1.65;-webkit-font-smoothing:antialiased}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;cursor:pointer;border:0;background:none;color:inherit}
页头:
css
复制
下载
.site-head{position:sticky;top:0;z-index:60;backdrop-filter:blur(14px);background:rgba(13,15,20,.86);border-bottom:1px solid var(--line)}
.head-in{max-width:1320px;margin:0 auto;padding:0 18px;height:66px;display:flex;align-items:center;gap:20px}
.logo{display:flex;align-items:center;gap:9px;font-weight:800;letter-spacing:.5px;flex:0 0 auto}
.logo svg{width:32px;height:32px}
.logo b{font-size:19px;background:linear-gradient(92deg,var(--mint),var(--amber));-webkit-background-clip:text;background-clip:text;color:transparent}
.nav{display:flex;gap:4px;margin-left:6px;overflow-x:auto;scrollbar-width:none}
.nav::-webkit-scrollbar{display:none}
.nav a{padding:8px 13px;border-radius:20px;font-size:15px;color:var(--dim);white-space:nowrap;transition:.22s}
.nav a:hover,.nav a.on{color:#08110e;background:var(--mint)}
嗯,导航悬停时用薄荷绿背景加暗色文字——可以。
搜索框:
css
复制
下载
.search{margin-left:auto;display:flex;align-items:center;gap:8px;background:var(--panel);border:1px solid var(--line);border-radius:22px;padding:7px 14px;min-width:200px}
.search input{background:none;border:0;outline:none;color:var(--txt);width:100%;font-size:14px}
移动端:隐藏搜索框,也许可以把导航缩一缩。
面包屑:
css
复制
下载
.crumb{max-width:1320px;margin:14px auto 0;padding:0 18px;font-size:13px;color:var(--dim)}
.crumb a{color:var(--mint)}
.crumb span{margin:0 6px;opacity:.5}
hero 区:
css
复制
下载
.hero{max-width:1320px;margin:16px auto 0;padding:0 18px;display:grid;grid-template-columns:1.55fr 1fr;gap:16px}
css
复制
下载
.hero-stage{position:relative;border-radius:18px;overflow:hidden;min-height:340px;border:1px solid var(--line);background:#11141b}
.slide{position:absolute;inset:0;opacity:0;transition:opacity .8s;display:block}
.slide.on{opacity:1}
.slide img{width:100%;height:100%;object-fit:cover}
.slide::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(8,10,14,.94) 12%,rgba(8,10,14,.55) 55%,rgba(8,10,14,.15))}
.hero-copy{position:absolute;left:0;bottom:0;padding:34px 30px;z-index:3;max-width:560px}
等等,hero-copy 应该放在轮播外面,这样它才能保持固定。但如果有多个 slide 各有各的文字……更简单的做法:一个文字块固定不动,图片轮换。行——把 hero-copy 放进 .hero-stage 里,用 z-index 3。
嗯,不过每张 slide 的文字会变……还是保留一套固定的文字吧。
其实再想一下:让 hero-stage 里放幻灯片,固定文字覆盖在上面,就是一套覆盖层。好。
指示圆点放在右下角。
hero-side:热搜榜列表。
css
复制
下载
.hero-side{background:var(--panel);border:1px solid var(--line);border-radius:18px;padding:16px 16px 8px}
列表项带排名数字。
然后是分类 chips。
接着进入主布局。
css
复制
下载
.layout{max-width:1320px;margin:0 auto;padding:0 18px 40px;display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:20px;align-items:start}
侧边栏粘性定位。
区块标题:
css
复制
下载
.sec-head{display:flex;align-items:flex-end;gap:12px;margin:30px 0 14px;padding-bottom:10px;border-bottom:1px solid var(--line)}
.sec-head h2{font-size:20px}
区块标题里带一条强调线。
卡片网格:
css
复制
下载
.grid-5{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:14px}
卡片:
css
复制
下载
.m-card{background:var(--panel);border:1px solid var(--line);border-radius:14px;overflow:hidden;cursor:pointer;transition:transform .28s cubic-bezier(.2,.7,.3,1),border-color .28s,box-shadow .28s;position:relative}
.m-card:hover{transform:translateY(-5px);border-color:rgba(92,225,185,.5);box-shadow:0 14px 30px -16px rgba(92,225,185,.45)}
海报区域的宽高比是 3/4。
更新徽标放在左上角。
然后是“编辑严选”区域——要不要做成横向的滚动列表?或者错落的行。那就做一个横向可滚动的细长卡片列表吧。
其实为了做出差异感,把“编辑严选”做成两列大卡片,横向排列——就像“特辑”那种感觉。
嗯,算了,就直接做成一个横向溢出滚动的细长卡片行,用 scroll-snap——在移动端体验不错。
新番速递:做成列表布局,在移动端左边缩略图、右边信息。
短剧改编漫画:横向滚动的卡片。
接下来是侧边栏:
热搜榜(排名列表)
编辑推荐(带缩略图的小列表)
题材标签云
追更日历(一周七天)
然后是资讯:带日期的文章卡片。
FAQ 用 details/summary 来做。
留言墙:评论卡片带头像、昵称、内容、时间、点赞数。
页脚:多个栏目带锚点链接、版权信息。
最后是 JSON-LD。
现在开始写,小心一点。
JS:
js
复制
下载
(function(){
// 轮播
var slides=document.querySelectorAll('.slide');
var dots=document.querySelectorAll('.dot');
var i=0;
if(slides.length){
setInterval(function(){
slides[i].classList.remove('on');
if(dots[i])dots[i].classList.remove('on');
i=(i+1)%slides.length;
slides[i].classList.add('on');
if(dots[i])dots[i].classList.add('on');
},4500);
}
// 弹窗
var modal=document.getElementById('detailModal');
...
})();
卡片点击:
js
复制
下载
document.querySelectorAll('.m-card').forEach(function(card){
card.addEventListener('click',function(e){
if(e.target.closest('.mini-btn'))return;
openModal(card);
});
card.addEventListener('keydown',function(e){if(e.key==='Enter'){openModal(card);}});
});
openModal 读取 data 属性。
关闭逻辑:点击遮罩层、点 ✕ 按钮、按 Esc 键。
追更按钮:
js
复制
下载
document.querySelectorAll('.mini-btn').forEach(function(b){
b.addEventListener('click',function(e){
e.stopPropagation();
if(b.classList.contains('done'))return;
b.classList.add('done');
b.textContent='已追更';
});
});
好。
接下来写卡片数据。
漫画列表——第一屏热播区(12 张卡片):
/upload/vod/001-manga.webp — 《剑起长安》 国漫 热血 更新至第 128 话 9.6
/upload/vod/007-anime.webp — 《午夜食堂异闻录》 日漫 治愈 更新至第 64 话 9.2
/upload/vod/012-tv.webp — 《深海图书馆》 悬疑 全集完结 9.4
/upload/vod/018-movie.webp — 《第七个夏天》 青春 更新至第 39 话 8.9
/upload/vod/024-variety.webp — 《