mole404 cac154aa07 feat(ui): 桌面端默认按 110% 呈现(等价浏览器整页缩放),并修好断点口径
老师习惯把浏览器整页缩放到 110% 用,希望默认就是这个状态;手机端必须不变。

一、为什么不能只写 zoom
- 浏览器整页缩放会让布局视口一起变小(1440 窗口在 110% 下页面眼里只有约 1309px),
  因此大断点不再命中、内边距变小、内容自然铺满两侧;
- 而 CSS zoom 只改布局尺寸、不改 media query 的判定宽度 → 断点照旧命中 →
  在 1536~1689.6 这一带会误命中 2xl:px-60(每侧多 220px 留白),
  在 768~844.8 这一带会误命中 md:(每侧多 17.6px)。这正是"缩放比例对了、排版没对"的根因。

二、做法
- tailwind.config.js:screens 的 md/lg/xl/2xl 全部 ×1.1(844.8 / 1126.4 / 1408 / 1689.6),
  sm 保持 640 不动(低于 768,改它会动手机)。
- resources/css/common.less:新增 @media(min-width:768px){html{zoom:1.1}},以及三个
  补偿类(.ls-zoom-minh-screen / .ls-zoom-h-screen / .ls-zoom-mt-0,带 html 前缀以压过
  app.css,因为 common.css 在它之前加载);同时覆盖 .container 的 max-width ——
  阈值 ×1.1 但值保持原值(Tailwind 把 max-width 写成断点值,跟着 ×1.1 会宽 1.1 倍),
  swal 动画档阈值同步 767→844.79。
- gallery.less:768/1024/1280/1536 四条阈值同步 ×1.1(640 不动,规则值是百分比)。
- blade:原先用 md:min-h-[calc(100vh/1.1)] 的 6 处改成 ls-zoom-minh-screen,弹窗的
  md:h-[…] 改成 ls-zoom-h-screen,容量块 md:mt-2 改成 ls-zoom-mt-0 ——
  必须换掉 md:,因为 md 现在是 844.8,而缩放从 768 就开,否则 768~844.8 会"开了缩放没补偿"。
- 侧栏左下角容量块:mt-10 → ls-zoom-mt-0(桌面多留 20.6px 底部余量,手机间距不动)。

三、验证(真 Chromium 153 + 真产物 CSS + 从真 blade 程序化抽取的同构 DOM)
- 18 档宽度(800~1920,含所有断点边界)A/B 对比:容器几何全部 ≤0.50px。
- 穷举指纹:7 类页面 × 4 档宽度、3468 个盒子,最大偏差 0.76px 横向 / 1.02px 纵向;
  横向残差仅来自 1.1 除不尽时的取整(W/1.1 为整数时塌到 0.25px),纵向残差是 CSS zoom
  自身的次像素累积(用无任何 media query 的合成页隔离验证,与断点无关)。
- 真实视口 390 及 640/700/767:与改动前逐项对比 1854 个盒子 Δ=0.0000(含 13~84 个具名指标/页)。
- 横向溢出:6 类页面 × 8 档宽度(390~2560)全部 0px。
- 容量块:1440×800 下底部余量 +20.61px(此前 +11.81px)。
- jsdom 290/290 全绿;三个钉住产物 md5 未变;Dockerfile 9 条 md5 自证逐条实算 9/9。
2026-10-01 11:36:15 +08:00
2022-05-08 10:13:10 +08:00
2026-09-30 21:23:12 +08:00

Lsky Pro Docker 镜像

基于 Lsky Pro 的自维护 Docker 镜像: 应用源码 vendored 在本仓库的 src/ 里,构建不联网拉上游,直接用本仓库内的源码。

  • 镜像:ghcr.io/mole404/lsky-pro-docker:latest (同一提交另发布不可变 tag:ghcr.io/mole404/lsky-pro-docker:sha-<完整 commit>)
  • 本仓库源码相对上游的偏离清单维护在 tools/diff-vs-upstream.sh,可随时用 bash tools/diff-vs-upstream.sh 自行核对。

快速开始

compose.yaml:

services:
  lsky-pro:
    image: ghcr.io/mole404/lsky-pro-docker:latest
    container_name: lsky-pro
    restart: unless-stopped
    ports:
      - "127.0.0.1:8089:8089"                 # 宿主端口:容器端口(WEB_PORT)
    volumes:
      - /root/lsky-pro/data:/var/www/html     # 站点数据全在这个目录里
    environment:
      - WEB_PORT=8089

等价的 docker run:

docker run -d --name lsky-pro --restart unless-stopped \
    -p 127.0.0.1:8089:8089 \
    -v /root/lsky-pro/data:/var/www/html \
    -e WEB_PORT=8089 \
    ghcr.io/mole404/lsky-pro-docker:latest

卷目录按你的实际情况改(上例是宿主 /root/lsky-pro/data)。上面把端口只绑到 127.0.0.1, 生产环境推荐这样,再在前面放一层 Nginx 反代终结 TLS。

首次安装与访问

  1. 容器起来后访问 http://<主机>:8089/,会自动跳到安装向导。
  2. 按向导填写数据库(默认 SQLite,镜像自带驱动,不需要额外数据库服务)与管理员账号。
  3. 安装结果写进卷里的 .env 与 database/ —— 也就是说备份卷就等于备份了配置与数据。

升级

docker compose pull
docker compose up -d          # 不需要 --force-recreate

同一个 tag 下镜像 digest 变了,compose 会自己重建容器。入口脚本会按版本标记把新代码同步进卷、 并作废编译视图缓存;.env / database/ / storage/ 等站点数据保持不变。

备份与恢复

备份

备份整个卷目录,别只抓 database.sqlite 一个文件:

docker compose stop lsky-pro
tar -C /root/lsky-pro/data -czf ~/lsky-backup-$(date +%F-%H%M).tar.gz .
docker compose start lsky-pro

为什么整目录:SQLite 开了 WAL(journal_mode=WAL),写入过程中的新数据会短暂落在同目录的 database.sqlite-wal / -shm 伴生文件里。只拷主文件可能拿到不一致的快照,整个目录一起打包 才是完整的。先停容器再拷最稳(单文件数据库运行中直拷最容易翻车)。

卷里哪些是数据、哪些是可替换代码:

  • 丢了不可再生,务必备份:.env(配置与密钥)、database/(SQLite 数据库)、 storage/(上传的图片、日志、会话)、bootstrap/cache/、public/thumbnails/、 public/i(本地存储策略的软链/目录)、installed.lock(已安装标记)。
  • 可重建,不用备份:app/、config/、resources/、routes/、public/js、public/css、 vendor/ 等 —— 它们就是镜像里的代码,换镜像时入口脚本会同步回去。

恢复

docker compose stop lsky-pro
mkdir -p /root/lsky-pro/data
tar -C /root/lsky-pro/data -xzf ~/lsky-backup-YYYY-MM-DD-HHMM.tar.gz
docker compose up -d

属主不用管:入口脚本每次启动都会对整卷做 chown -R www-data + chmod -R 755。 换机器迁移 = 把归档解到新机器的卷目录 + 复用同一份 compose.yaml。

常见配置

端口与证书

环境变量 默认值 说明
WEB_PORT 8089 容器内 Apache 的 HTTP 监听端口
HTTPS_PORT 8088 容器内 HTTPS 端口(自签证书,仅供内网调试)

自签证书落在容器里的 /etc/apache2/ssl/lsky-selfsigned.crt 与 .key(CN=lsky-pro,RSA 2048, 3650 天),不随镜像发货、也不进数据卷:每个容器首次启动自己生成,重建容器会重新生成。 想用自己的证书,把 .crt / .key 挂载到这两个路径覆盖即可(入口脚本见到文件已存在就跳过生成)。

Apache MPM(并发与内存)

镜像内置一套面向低配单用户的参数,覆盖 Apache 的出厂值。每一项都能逐项用环境变量覆盖, 写哪个改哪个、没写的保持默认:

环境变量 默认值 说明
APACHE_START_SERVERS 2 启动时预建的子进程数
APACHE_MIN_SPARE_SERVERS 1 空闲子进程下限
APACHE_MAX_SPARE_SERVERS 3 空闲子进程上限
APACHE_MAX_REQUEST_WORKERS 5 并发请求上限(内存占用的主要来源)
APACHE_MAX_CONNECTIONS_PER_CHILD 5 单个子进程处理多少个请求后回收(0 = 永不回收)
APACHE_KEEP_ALIVE Off 只接受 On / Off;Off 时连接用完即关,最省内存

另有两个可选变量,只在 APACHE_KEEP_ALIVE=On 且显式设置时才各多写一行,不设就跟随 Apache 发行版默认(KeepAliveTimeout 5 秒 / MaxKeepAliveRequests 100):

环境变量 渲染出的行
APACHE_KEEPALIVE_TIMEOUT KeepAliveTimeout <值>(仅 KeepAlive On 时)
APACHE_MAX_KEEPALIVE_REQUESTS MaxKeepAliveRequests <值>(仅 KeepAlive On 时)

写了非法值只会把那一项退回默认值并在日志打一行警告,不会让容器起不来。取值按 「一个 Apache 子进程跑起 Laravel 后 ≈ 30–50MB」估算 MaxRequestWorkers × 单进程内存 ≤ 机器可用内存, 宁小勿大 —— 超了被 OOM 杀掉比排队慢得多。

许可与致谢

S
Description
兰空图床 个人自用修改版
Readme AGPL-3.0
18 MiB
0 Stars 1 Watchers 0 Forks
Languages
Blade 38.2%
JavaScript 24.7%
PHP 24.6%
Shell 6.9%
Less 2.7%
Other 2.9%