ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Jellyfin自定义CSS换肤实战:从样式注入到版本升级排查

Jellyfin自定义CSS换肤实战:从样式注入到版本升级排查 1. 默认界面看腻了先说清楚Jellyfin自定义CSS到底动了什么Jellyfin这套开源媒体服务器功能没得挑刮削、转码、多用户、多端同步都做得挺扎实。但默认Web界面说句实在话属于能用但不够好看那一挂。底子用的是十几年前那套Web UI框架的演化版本配色中规中矩卡片间距偏松散部分按钮、徽章、阴影效果堆在一起信息层级不够清爽。尤其当你用4K电视浏览器或者大屏NAS上直接打开时细节粗糙感会被放大得很明显。于是大家开始打CSS的主意。用CSS给Jellyfin换肤这件事本质上就是在不触碰核心媒体服务逻辑的前提下对Web前端表现层做定制。它不影响你的媒体库结构、不影响解码转码、不影响用户权限纯粹改变浏览器里看到的样子。所以哪怕你对前端不熟只要肯花半小时读懂几条CSS规则就能把一个默认脸的Jellyfin调成自己的风格。需要先打破一个误区Jellyfin自定义CSS并不要你从头写一整份样式表。它的机制是在你当前主题之上叠加覆盖层你只需要精准写出你想改的那部分规则就能盖住默认样式。这就比很多人想象得轻量很多。哪怕你只会浏览器开发者工具里的检查元素也能一步步定位到想要修改的目标写出一条background-color或者调整某个margin刷新页面就能看到效果。这篇内容我会从环境准备、样式注入方式、具体实战案例到版本升级的踩坑排查完整走一遍。适合刚接触Jellyfin、想给媒体库换个观感的玩家也适合有一定CSS基础但不知道怎么定位Jellyfin界面元素的朋友抄作业。全程不涉及复杂的构建工具不搞Node环境不搞打包就靠浏览器自带的能力完成调试你需要的只是耐心和一点点动手欲望。2. 自定义CSS注入的几种姿势以及我为什么最终推荐内置配置Docker挂载组合2.1 先搞清楚你的Jellyfin跑在哪里不同部署方式决定了你的CSS注入路径完全不同。官方支持的平台很多Windows安装包、Linux安装包、Docker容器、NAS套件群晖/威联通等、甚至国产NAS系统里自带的Docker应用。我自己的主力环境是Docker Compose部署所以后文绝大多数路径说明会以容器场景为例但内置CSS配置项这个功能在所有部署形态里都一样保存即生效不涉及重启容器。如果你是Windows安装包或Linux包安装的JellyfinCSS直接写在Web根目录下也能生效但有个致命问题Jellyfin更新时会把整个Web目录替换掉你放在里面的自定义文件会被清空。这不是什么bug而是官方为了升级一致性做的覆盖策略。所以我现在强烈建议——不要直接改安装目录里的静态文件而是用官方预留的扩展机制来注入样式。2.2 内置Custom CSS配置项这是最稳妥的入口打开Jellyfin后台依次进入控制台-高级往下翻能看到Custom CSS文本框。这个文本框里填什么最终会被原样注入到Web界面的head区域以style块的形式输出到每个页面。它的加载时序在页面渲染最早期所有内容元素还没开始绘制之前就已经就位所以你在里面写的覆盖规则可以正常参与CSS层叠计算不会被默认样式的加载顺序碾压。实际操作中我建议把这份CSS拆成两个层次。第一层是基础变量层只放CSS自定义属性变量定义比如主题色、卡片圆角、间距、字体。第二层是组件覆盖层放针对具体组件类名的规则。后面我会详细给出一套可直接套用的模板这里先记住结论内置Custom CSS适合放不依赖外部文件、纯CSS内容的代码因为文本框不可能让你直接引用一个磁盘路径下的.css文件。2.3 Docker Compose环境下的额外选择直接挂载custom.css如果你是Docker部署除了内置Custom CSS文本框还有一种灵活性更高的方式自己创建一份custom.css文件挂载到容器内/jellyfin/jellyfin-web/目录下然后在Custom CSS文本框里用import url(custom.css);引入。为什么我会推荐这个组合两个原因。第一文本框里编辑长CSS的体验非常糟糕。Jellyfin后台那个文本框没有代码高亮、没有格式化、不小心点错还会丢内容。而挂载外部文件后你在宿主机上用VS Code打开编辑保存刷新浏览器即可看到效果配合浏览器的自动刷新插件调试效率高一个量级。第二方便备份和版本管理。CSS是长期迭代的一套东西你不可能一次写好就再也不动。把它放在宿主机的一个目录里比如./config/jellyfin/custom.css天然纳入你的Compose配置管理。将来换机器、重部署把整个config目录带过去就行不需要重新从文本框复制。挂载方法很简单。在docker-compose.yml中给jellyfin服务添加一个volumeservices: jellyfin: image: jellyfin/jellyfin:latest container_name: jellyfin restart: unless-stopped ports: - 8096:8096 volumes: - ./config:/config - ./cache:/cache - ./media:/media - ./jellyfin-web/custom.css:/jellyfin/jellyfin-web/custom.css然后在后台Custom CSS文本框里写一行import url(custom.css);保存后刷新页面如果custom.css文件本身没有语法错误你的样式就会生效。注意不同版本Jellyfin的容器内Web目录路径可能会变。较老版本是/usr/share/jellyfin/web比较新的版本如果基于容器镜像重构路径可能变成/jellyfin/jellyfin-web。我自己遇到过路径变化导致挂载失效的情况。排查方法很简单进容器看一眼docker exec -it jellyfin ls /找到实际Web目录再调整挂载路径别想当然。3. 从零开始的第一组主题样式摸清DOM、写下第一条覆盖规则3.1 先学会用检查命令定位Jellyfin界面元素任何CSS定制工作的第一步不是写代码而是定位。你调整的是Jellyfin界面首先得知道你想改的那个元素在HTML里长什么样、挂在哪一层、有什么类名和属性。打开Jellyfin主页按F12打开浏览器开发者工具左上角有个箭头图标通常叫Inspect或检查元素。点它然后在页面里单击你想改变的视觉元素。比如你觉得主页面背景太刺眼点一下空白区域觉得某个卡片太矮点一下卡片封面区域。这一下会直接定位到DOM树上对应节点。此时你注意看右侧的Styles面板它展示的是这个元素继承到的所有CSS规则。Jellyfin界面的类名体系很杂乱很多类名带了很多前缀比如.card、.cardBox、.cardContent、.emby-scroller、.skinHeader、.mainDrawer等等。这是历史遗留的累赘命名你要做的是在检查面板里多翻几个层级找到目标类名然后才能写好覆盖规则。举一个实际场景。我想隐藏首页顶部那一排分类按钮我的媒体收藏续播之类的好几个tab在检查面板里点那个按钮发现它的类名带有.emby-tabs这类特征。那么我在custom.css里就可以写/* 隐藏顶部tab栏 */ .skinHeader .emby-tabs { display: none !important; }注意这里我加了!important。为什么Jellyfin默认样式表里对很多组件设置了优先级非常高的选择器有些带!important有些多层嵌套。你后加载的CSS如果不加!important在层叠竞争里不一定能赢。但对日常覆盖来说这算是一种简单粗暴的兜底手段后面我会讲更优雅的处理方法。3.2 一套可以直接抄的基础模板下面这份模板是我自己维护的custom.css的极简版适合作为起点。你先复制到你的custom.css文件里再逐行理解它在做什么/* 基础主题变量 */ :root { --jf-primary-color: #00a4dc; /* 主题色Jellyfin默认偏蓝 */ --jf-bg-color: #141414; /* 全局背景色 */ --jf-card-radius: 16px; /* 卡片圆角 */ --jf-card-shadow: 0 4px 12px rgba(0,0,0,0.3); /* 卡片阴影 */ --jf-text-muted: #aaaaaa; /* 弱化文字颜色 */ } /* 全局背景 */ body, .backgroundContainer { background-color: var(--jf-bg-color) !important; background-image: none !important; } /* 卡片网格间距调整 */ .emby-scroller { --card-width: 280px; /* 调整卡片宽度影响一行显示的卡片数量 */ } .card { border-radius: var(--jf-card-radius) !important; box-shadow: var(--jf-card-shadow) !important; transition: transform 0.2s ease, box-shadow 0.2s ease; } /* 卡片鼠标移入效果 */ .card:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(0,0,0,0.45) !important; } /* 隐藏首页我的媒体分类上方多余的视图类型下拉按钮 */ .viewTypeButtons { display: none !important; } /* 已观看标识别针锋相对改成删除线 */ .itemProgressBar .progressbar { height: 3px !important; background: rgba(255,255,255,0.12) !important; } .itemProgressBar .progressbar .progress { background: var(--jf-primary-color) !important; } /* 弱化页脚信息 */ .footer { color: var(--jf-text-muted) !important; }这里面有两条规则特别值得展开说明。第一--card-width是一个CSS变量Jellyfin自己的样式表里定义了它用来控制卡片横排时的宽度。你直接改这个变量比去改每个.card的宽度要高效得多因为网格布局的列数就是根据这个宽度和容器总宽自动计算的。第二.card:hover这条规则里我用了transform: translateY(-4px)和阴影增强实现鼠标悬停时卡片轻微上浮的效果。这是页面交互里最立竿见影的视觉提升CSS过渡动画只写了0.2s ease不会做出那种很廉价的弹跳感而是干净的位移。3.3 三行模式的CSS从一个热搜词说开去你如果查三行模式的css文件这样的热词很可能是有人在问如何用少量代码实现高效覆盖。这里我给大家一个三行起步的思路也是我自己给任何一台新Jellyfin快速换肤的最小动作:root { --jf-primary-color: 你的主题色; } .backgroundContainer { background-color: #141414 !important; } .card { border-radius: 16px !important; }就这三行已经能改变整个浏览观感主题色管所有可点击按钮、焦点框、进度条的颜色背景色管整体氛围卡片圆角管所有封面、海报的造型。先跑通这三行确认注入链路是通的再继续往细节走。这个最小化验证思路非常重要。因为Jellyfin的自定义CSS有时候不生效不是样式写得不对而是你的加载链路出问题了。你要用最少的代码先验证链路通不通而不是一上来就贴一大段代码结果分不清是链路问题还是规则问题。4. 高频视觉需求逐个击破字体、居中、删除线、鼠标悬停和动画写完基础模板后你会开始遇到具体的、零散的需求这个按钮的字体想换、那个文字想居中、想看删除线效果、想加个涟漪光圈动画。这些都属于CSS的基础能力但在Jellyfin的组件体系里你得知道对应的类名和上下文才能写对。下面我把我实际做过的几个高频场景拉出来讲。4.1 字体渐变和外描边让标题区域有质感很多人的第一视觉升级点是首页左上角那个媒体库名称或者海报标题。Jellyfin里的标题元素通常带有.pageTitle或者.detailPageWrapper .parentName等类名。给它加字体渐变的CSS规则效果很出彩.pageTitle { font-size: 1.8em !important; font-weight: 700 !important; background: linear-gradient(135deg, #00a4dc 0%, #7b2ff7 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; background-size: 100% 100%; }这条规则的原理先用渐变背景填充整个文字区域再把背景裁剪到文字形状内最后把文字原本颜色设为透明这样你看到的就是渐变色的字形。如果想要外描边让文字在浅色海报背景下依然清晰可读可以在上面基础上加text-shadow但注意text-shadow在background-clip: text模式下会和透明文字冲突效果会打折扣。我的做法是用两层text-shadow模拟外描边.customTitle { text-shadow: -1px -1px 0 rgba(0,0,0,0.8), 1px -1px 0 rgba(0,0,0,0.8), -1px 1px 0 rgba(0,0,0,0.8), 1px 1px 0 rgba(0,0,0,0.8); }四方向偏移各1px叠加起来就是一个完整的描边轮廓。这个方法适合给文字加描边效果视觉上干净利落。4.2 文本垂直水平居中的两个正确姿势做CSS定制时经常遇到我想把这个文字放在卡片的右上角或者让这一行字垂直居中。Jellyfin很多组件本身就用了flex布局所以最可靠的居中方案是flexbox。.someBannerContainer { display: flex; align-items: center; /* 垂直居中 */ justify-content: center; /* 水平居中 */ }但有时候你改的容器不是flex强行加display:flex可能会破坏原有布局。这时候用传统的text-align配合line-height也能实现单行文字的垂直居中让容器的height和line-height相等文字就被行高顶到中间了。.someTabButton { height: 40px; line-height: 40px; text-align: center; }这个方法只适用于单行文本多行文本千万不要用否则文字会重叠。我自己用过这个方案去微调Jellyfin详情页里演员姓名在卡片内的位置效果很稳定。4.3 删除线给已观看媒体一个明确的视觉标记热搜词里提到css 删除线在Jellyfin场景里最常见的用法是给已观看的内容加一条贯穿线。Jellyfin本身用封面图标上的勾选标记来表示已观看但那个标记很小在缩放比例较低的电视屏幕上几乎看不清。你可以用删除线让已观看的标题文字直接划掉一眼分辨哪些看过了/* 已观看的项目标题加删除线 */ .item .cardContent .cardText .cardText-first[data-readtrue], .cardText[data-readtrue] { text-decoration: line-through !important; text-decoration-thickness: 2px; color: #777 !important; }不过这里有个隐藏问题Jellyfin的标题元素并不总是挂>.card[data-typeEpisode] .cardText[data-readtrue] { text-decoration: line-through !important; opacity: 0.65; }opacity: 0.65再加删除线视觉层次很清晰。这条规则对剧集列表特别好用因为剧集标题很短删除线一眼就能扫到。4.4 鼠标移入事件用:hover做卡片互动和涟漪光圈热搜词里css 鼠标移入事件说的就是:hover伪类。我在基础模板里已经演示了卡片悬停上浮这里再讲一个进阶玩法涟漪光圈扩散。这种效果的灵感来自Material Design的波纹反馈。在Jellyfin的封面卡片上实现一个光圈从中心向外扩散的动画核心是两层一层是定位用的伪元素一层是keyframes动画。.card { position: relative; overflow: hidden; } .card:hover::after { content: ; position: absolute; left: 50%; top: 50%; width: 0; height: 0; background: rgba(255, 255, 255, 0.15); border-radius: 50%; transform: translate(-50%, -50%); pointer-events: none; animation: ripple 0.6s ease-out forwards; } keyframes ripple { from { width: 0; height: 0; opacity: 1; } to { width: 400px; height: 400px; opacity: 0; } }这段代码渲染出来就是鼠标进入卡片时从中心点扩散一个半透明圆环最后淡出。视觉冲击力很直接。但我也要提醒动画元素多了会影响性能尤其连续浏览海报墙时每个卡片hover都触发一次动画低端NAS上浏览器画面会掉帧。建议动画只加在首页第一屏或者干脆删掉只保留上浮效果。4.5 盒模型间距调不对十有八九是盒模型没搞清热搜词里反复出现css从入门到精通——盒模型可见这个概念的普及度也说明它是很多人卡壳的根源。Jellyfin界面的间距问题几乎都能用盒模型知识解释清楚。盒模型说的是每个元素都有一层边框、内边距、外边距从内到外是内容区、padding、border、margin。调整间距时你要分辨现在这个元素和隔壁元素之间的空隙到底来自哪个盒子层。实战中我遇到过这样的案例详情页的演员列表和下方相关推荐靠得太近我以为是外层容器的margin-bottom不够加了半天没效果。后来检查发现空隙是演员列表内部每张卡片底部的margin-bottom叠加出来的调整容器margin完全没用。正确做法是给演员卡片区域的外层容器加padding-bottom把内部元素的间距撑开。/* 给详情页底部区域增加呼吸感 */ .detailPageWrapper .castSection { padding-bottom: 40px !important; }所以当你觉得页面某个区块挤得慌先去开发者工具里定位元素看它当前的margin和padding数值再决定改哪一边。不要凭感觉乱加。4.6 动画和过渡给界面加一点克制的动效Jellyfin默认是没有任何过渡动画的所以页面切换、面板展开都比较生硬。你用CSS可以很轻松地加上过渡效果让所有变化都柔和一些/* 所有可交互元素的变化都加上过渡 */ button, .card, a { transition: transform 0.2s ease, color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease; } /* 侧边抽屉展开时淡入 */ .mainDrawer { transition: transform 0.3s ease, opacity 0.3s ease; }注意两点。一是过渡动画的时间别太长0.2秒到0.35秒是舒适区间超过0.5秒会让人觉得界面拖泥带水。二是所有元素无差别加过渡会让某些场景显得迟缓比如切tab按钮的变色0.2秒是恰到好处的。4.7 段落分割线用CSS理清信息区块Jellyfin详情页的内容层级比较乱导演、演员、剧情简介、幕后花絮全都堆在一起没有明显的分隔。热点词里css实现段落分割线正好解决这个问题。用伪元素给区块之间加一条细腻的分割线.detailPageWrapper .sectionTitle { border-bottom: 1px solid rgba(255, 255, 255, 0.15); padding-bottom: 8px; } .detailPageWrapper .childContent { margin-bottom: 30px; padding-bottom: 30px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); }这样每个区块底部都有一条浅色线信息层级瞬间清晰。分割线的颜色我用的是rgba(255,255,255,0.1)这种低透明度白色在深色背景下是一条很淡的灰色线不会抢焦点。如果以后想换浅色主题改成rgba(0,0,0,0.1)即可。4.8 滚动条美化细节决定质感这是被很多人忽略但提升效果显著的一个点。Windows下默认滚动条又宽又白在深色Jellyfin界面里非常扎眼。用几行CSS把它改成细窄的暗色滚动条::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2); border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.35); }这段代码只对WebKit内核浏览器生效Chrome、Edge都支持Firefox需要额外的scrollbar-color语法。Jellyfin用户群主要在浏览器的场景下Chrome系和Edge占绝对多数所以写了这个基本就够了。我自己的实测感受是滚动条变细之后媒体库的精致感立即上了一个台阶。5. 版本升级样式失效别慌按这个链路排查5.1 失效的第一个可能挂载路径变了Jellyfin的版本迭代很勤尤其是紧跟Emby那边变更的版本Web目录的布局调整频率更高。你升级之后发现custom.css里的样式全部失效第一时间要检查的就是挂载路径是否仍然指向正确的Web目录。我之前有过一次惨痛经历Jellyfin从某个版本升到新版容器里的前端资源目录从/usr/share/jellyfin/web改成了/jellyfin/jellyfin-web我的Compose挂载还指向旧路径导致custom.css这个文件根本没有出现在新容器的Web目录里。但奇怪的是Custom CSS文本框里的import url(custom.css)不报错只是找不到文件静默忽略。这时候页面上所有自定义样式全部消失非常容易被误判成代码写错了。碰到这种问题正确姿势是# 进入容器确认实际Web目录路径 docker exec -it jellyfin sh ls /jellyfin/jellyfin-web/custom.css如果文件不存在说明挂载位置不对检查Compose调整路径重新创建容器。5.2 失效的第二个可能选择器锚定的结构变了升级后部分样式失效但部分还在这是最典型的情况。比如你之前用的.cardContent这套类名可能在新版里被改了前缀或者调整了嵌套层级。排查方法非常直白F12打开开发者工具点击那个失效的元素看它在DOM里现在实际用的类名跟你CSS里写的是否一致。我曾经遇到过.emby-scroller这个类名从滚动容器转移到了外层包装上导致我针对它写的--card-width变量完全失效。检查之后发现新版里卡片宽度变量移动到了.crystalScroller或者类似的新类名上我把规则改到新类名才恢复效果。5.3 排查思路二分法隔离问题源样式失效的排查强烈建议用二分法先清空custom.css里所有内容只留一条最显眼的规则比如把背景改成红色。刷新页面。如果红色背景生效说明注入链路和文件挂载没问题问题锁定在你原来那堆样式中某几条。如果红色背景不生效说明链路断了回到5.1检查文件是否存在、import是否拼写正确。确认链路正常后把你原来那一大段CSS代码逐段放回去每次放一小块刷新看那一块是否生效。哪一块不生效就去对应元素检查最新类名。这个方案我用了很多次能在几分钟内把问题从一大堆样式缩小到某一条规则。别一上来就整段替换。5.4 永久有效的本土方法给选择器加版本号兜底我自己有个习惯在关键覆盖规则尾部加一个不显眼的注释注明这个规则是针对哪个Jellyfin版本调通的。这样你升级后发现它挂了能快速定位到这是老版本专用样式而不是新写的没调好。/* [jf 10.8.13] 隐藏详情页评分图标 */ .detailPageWrapper .starRatingContainer { display: none !important; }这套版本锚定的做法在Jellyfin社区里也很常见很多别人的CSS配置里也会写版本号。你维护自己的custom.css时也可以借鉴。毕竟Jellyfin更新频率不低一份样式表长期使用必然经历多次适配。6. 调试效率与长期维护用好变量、折叠块和浏览器缓存6.1 用CSS变量统一管理主题色改一个值全站翻新前面基础模板里我用了:root里的CSS变量。这也是我要重点强调的长期维护手段。如果所有主题色都写死成十六进制色值将来想换个色调你得全文查找替换几十处。但用变量定义一次后面所有规则都引用var(--jf-primary-color)改一行全站生效。这个习惯对Jellyfin特别重要因为它的界面元素太多主题色用在按钮、焦点框、进度条、高亮文字、选中状态可能上百处。不用变量改一次主题色就是一个灾难。以下是我常用的一组变量清单你可以在自己的CSS里再扩展:root { --jf-primary-color: #00a4dc; --jf-primary-color-hover: #00b4f0; --jf-primary-color-active: #008fc0; --jf-bg-color: #141414; --jf-surface-color: #1e1e1e; --jf-text-color: #dddddd; --jf-text-muted: #888888; --jf-card-radius: 14px; --jf-card-gap: 18px; --jf-scrollbar-size: 8px; }注意Jellyfin自己内部也有一套CSS变量体系比如--emby-theme-background之类的版本不同变量名也不稳定。我一般不去动它的内部变量只在:root里定义我自己的在具体覆盖规则里引用我的变量降低耦合。6.2 在custom.css里建立清晰的区块注释自定义CSS写到后面会越来越长几百行都很正常。如果没有良好的区块注释三个月后回来看完全看不懂自己当初写了什么、为什么这样写。我建议按功能模块划分区块并注明每块的用途和适用页面。/* [1] 全局基础变量 */ /* [2] 布局与间距覆写首页网格、卡片间距 */ /* [3] 详情页组件覆写演员列表、剧情区块 */ /* [4] 播放页覆写播放按钮、控制栏 */ /* [5] 侧边栏与导航覆写 */ /* [6] 滚动条与交互动效 */每个区块内部规则按照从外到内、从粗到细的顺序排列。真实经验是最先写的那一批临时测试规则最容易污染文件——它们是那次调试时的探路石但事后忘了删后续会干扰更精确的覆盖。所以我会定期做一次清理过期规则的维护把明显失效的、被新规则替代的、注释掉的旧代码删除。保持文件精简比什么都重要。6.3 浏览器缓存改完没生效先别怪代码Jellyfin的Web资源在浏览器里缓存策略很积极用户端浏览器会缓存CSS和JS文件。你改了custom.css但页面刷新后看到的还是老样式不用怀疑规则没生效大概率是浏览器缓存了旧的CSS文件。解决办法在Chrome开发者工具打开状态下长按刷新按钮选择清空缓存并硬性重新加载。或者更简单在custom.css文件路径后面加一个版本查询参数import url(custom.css?v20240910);这样改一次版本号就能强制所有客户端重新下载。很多人在群里问为什么改了没反应我第一反应就是让他们改这个版本号。等你调试稳定后可以把?v参数固定下来避免每次刷新都浪费请求。注意import里的URL如果带?参数缩进和引号必须标准否则整个引入会被浏览器忽略样式全无。如果遇到加了版本号后反而所有样式消失的情况检查引号和分号是否完整。6.4 局部覆盖和全局覆盖控制粒度Jellyfin的自定义CSS是全局生效的意味着你写的每一条规则会影响所有页面、所有设备尺寸。粒度控制不好会出现很尴尬的问题比如你在电视上调试好的卡片宽度在手机上打开媒体库时变得拥挤不堪。所以我的原则是能用media媒体查询区分场景的就尽量区分/* 大屏设备电视、PC用宽卡片 */ media (min-width: 1200px) { .card { --card-width: 320px; } } /* 手机端用窄卡片 */ media (max-width: 768px) { .card { --card-width: 160px; } }这样在各端都能得到合理的布局。Jellyfin用户通常不止一个终端访问手机、平板、电视、PC浏览器都可能同时接入。一份不考虑响应式的自定义CSS迟早会在这里或者那里翻车。6.5 分享和备份给主题打上存档点当你终于把样式调到满意状态千万别忘了备份。我自己是每完成一个阶段的样式调整就把custom.css复制一份带日期后缀的存档比如custom_20250101.css。不是因为怕丢而是因为CSS这种东西改起来很容易越改越乱存档能让你随时退回某个状态。Jellyfin社区也有不少现成主题可以借鉴比如社区里流传的各种“深色主题”“毛玻璃主题”。你可以直接搜来用。但我的经验是别人的主题终归是别人的审美而且是为他那个版本调通的搬到自己环境里大概率要改。更好的做法是把它们的核心思路比如某些组件的覆盖方式抽出来改写成自己变量体系下的规则再融入到自己的custom.css里。7. 最后再分享一点我的个人习惯玩Jellyfin自定义CSS这件事本质上是在给一个功能很全但视觉平庸的开源项目做精装修。它不需要你有很深的前端功底但要求你养成一个习惯每一次改动前先在开发者工具里把目标元素看清楚再动CSS。我见过太多人上来就复制一片网上的CSS也不管选择器匹配的是哪个元素最后改半天没效果反而对自定义CSS产生了抵触情绪。我自己现在维护custom.css的方式很简单日常使用中发现哪里不顺眼就F12定位写一条规则标上版本注释放回对应区块。坚持三个月这份文件就会成为你专属的Jellyfin视觉定制档案换设备、重装系统、升级版本都能快速恢复到自己舒服的界面状态。还有个小技巧收尾如果你给某台设备比如客厅的电视盒子专门优化了界面布局但其他设备看会有点怪异可以考虑在custom.css里给那台设备设置一个特征变量比如按屏幕比例或分辨率命中特定规则。不过这个需求比较小众大多数人维护一份全局样式就够了。先把基础打好再按自己的实际需求慢慢扩展这条路任何人都能走通。
返回列表