From 789c8ac5bc794791bcc84cf72b77a4718393e19d Mon Sep 17 00:00:00 2001 From: cqh963852 Date: Tue, 6 Oct 2026 13:38:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=A5=A8=E5=88=B8=E6=89=93=E5=AD=94?= =?UTF-8?q?=E6=94=B9=20mask=20=E5=B7=AE=E9=9B=86=E2=80=94=E2=80=94?= =?UTF-8?q?=E4=B8=A4=E7=AB=AF=201/4=20=E5=9C=86=E7=A1=AC=E5=81=9C=E5=89=AA?= =?UTF-8?q?=E5=88=87=EF=BC=8C=E5=AD=94=E7=9C=9F=E7=A9=BF=E9=80=8F=E9=9C=B2?= =?UTF-8?q?=E5=BA=95=E3=80=81=E6=8F=8F=E8=BE=B9=E7=9C=9F=E6=96=AD=E5=BC=80?= =?UTF-8?q?=EF=BC=9B=E5=AD=94=E5=BF=83=E5=AF=B9=E9=BD=90=E6=92=95=E7=BA=BF?= =?UTF-8?q?=20172.75px?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/design-lab/e2e/pages.spec.ts | 18 ++++++++++------ apps/design-lab/src/styles/tokens.css | 30 ++++++++++++--------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/apps/design-lab/e2e/pages.spec.ts b/apps/design-lab/e2e/pages.spec.ts index 03cd7a0..cf7d179 100644 --- a/apps/design-lab/e2e/pages.spec.ts +++ b/apps/design-lab/e2e/pages.spec.ts @@ -140,13 +140,19 @@ test.describe('票券规格契约', () => { expect(s.headBg).not.toBe('rgba(0, 0, 0, 0)') }) - test('打孔伪元素在位(完成票 ×2 孔)', async ({ page }) => { - const holes = await page.locator('.ticket-pk').first().evaluate((el) => { - const b = getComputedStyle(el, '::before') - const a = getComputedStyle(el, '::after') - return [b.content, a.content].filter((c) => c !== 'none').length + test('打孔差集在位(mask 两端 1/4 圆,完成票)', async ({ page }) => { + const mask = await page.locator('.ticket-pk').first().evaluate((el) => { + const cs = getComputedStyle(el) + return cs.maskImage || cs.webkitMaskImage || 'none' }) - expect(holes).toBe(2) + expect(mask).toContain('radial-gradient') + expect(mask.split('radial-gradient').length - 1).toBe(2) // 上下各一孔 + // 未开始票不带 mask + const plain = await page.evaluate(() => { + const t = [...document.querySelectorAll('div')].filter((d) => String(d.className).includes('w-[216px]') && !String(d.className).includes('ticket-pk'))[0] + return t ? getComputedStyle(t).maskImage : 'none' + }) + expect(plain === 'none' || plain === '').toBeTruthy() }) test('撕线:完成=虚线、未开始=实线', async ({ page }) => { diff --git a/apps/design-lab/src/styles/tokens.css b/apps/design-lab/src/styles/tokens.css index 2ca5f2f..cacddaf 100644 --- a/apps/design-lab/src/styles/tokens.css +++ b/apps/design-lab/src/styles/tokens.css @@ -32,21 +32,17 @@ filter: drop-shadow(0 1px 0 rgba(255, 255, 255, 0.9)); } -/* 票券打孔:⌀14 圆跨边,被 overflow-hidden 裁成半圆缺口(完成票专用) */ -.ticket-pk::before, -.ticket-pk::after { - content: ''; - position: absolute; - left: 160px; - width: 14px; - height: 14px; - border-radius: 50%; - background: var(--color-paper); - border: 2px solid var(--color-ink); -} -.ticket-pk::before { - top: -10px; -} -.ticket-pk::after { - bottom: -10px; +/* 票券打孔:两端各以 1/4 圆做差集(完成票专用)。 + * mask 硬停只做形状剪切(非色彩渐变):孔真正穿透票体——露出页面底色, + * 描边与硬投影在孔处真实断开,无需伪元素盖色近似。 */ +.ticket-pk { + --hole-x: 172.75px; /* 撕线中心:216 − 右描边 2 − stub 42 + 撕线半宽 */ + -webkit-mask-image: + radial-gradient(circle 7px at var(--hole-x) 0, transparent 6.5px, #000 7px), + radial-gradient(circle 7px at var(--hole-x) 100%, transparent 6.5px, #000 7px); + -webkit-mask-composite: source-in; + mask-image: + radial-gradient(circle 7px at var(--hole-x) 0, transparent 6.5px, #000 7px), + radial-gradient(circle 7px at var(--hole-x) 100%, transparent 6.5px, #000 7px); + mask-composite: intersect; }