From 60c497797501c32e0734769effb2d57f5a322438 Mon Sep 17 00:00:00 2001 From: Frederick O'Brien Date: Thu, 21 May 2026 17:11:48 +0100 Subject: [PATCH 1/2] Make centre rule configurable in grid API --- .../src/components/GalleryCaption.tsx | 24 --------- .../src/components/GalleryImage.tsx | 7 ++- dotcom-rendering/src/grid.ts | 53 +++++++++++++------ 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/dotcom-rendering/src/components/GalleryCaption.tsx b/dotcom-rendering/src/components/GalleryCaption.tsx index 26a71ba6205..9b5cf754a00 100644 --- a/dotcom-rendering/src/components/GalleryCaption.tsx +++ b/dotcom-rendering/src/components/GalleryCaption.tsx @@ -31,34 +31,10 @@ const styles = css` ${between.desktop.and.leftCol} { ${grid.column.right} - - position: relative; /* allows the ::before to be positioned relative to this */ - - &::before { - content: ''; - position: absolute; - left: -10px; /* 10px to the left of this element */ - top: 0; - bottom: 0; - width: 1px; - background-color: ${palette('--article-border')}; - } } ${from.leftCol} { ${grid.column.left} - - position: relative; /* allows the ::before to be positioned relative to this */ - - &::after { - content: ''; - position: absolute; - right: -11px; - top: -12px; - bottom: 0; - width: 1px; - background-color: ${palette('--article-border')}; - } } `; diff --git a/dotcom-rendering/src/components/GalleryImage.tsx b/dotcom-rendering/src/components/GalleryImage.tsx index 5ce317dcd10..5a37ed732c7 100644 --- a/dotcom-rendering/src/components/GalleryImage.tsx +++ b/dotcom-rendering/src/components/GalleryImage.tsx @@ -22,8 +22,9 @@ type Props = { }; const styles = css` + overflow: hidden; ${grid.paddedContainer} - ${grid.verticalRules()} + ${grid.verticalRules({ plusChild: 1 })} grid-auto-flow: row dense; background-color: ${palette('--article-inner-background')}; @@ -34,7 +35,9 @@ const styles = css` ${from.desktop} { &:first-of-type { - padding-top: ${space[3]}px; + & > * { + padding-top: ${space[3]}px; + } } } `; diff --git a/dotcom-rendering/src/grid.ts b/dotcom-rendering/src/grid.ts index f60ae0ffc5d..4aec02a60c2 100644 --- a/dotcom-rendering/src/grid.ts +++ b/dotcom-rendering/src/grid.ts @@ -88,36 +88,58 @@ const paddedContainer = ` // ----- Vertical Rules ----- // type VerticalRuleOptions = { - centre?: boolean; color?: string; + plusChild?: number; }; /** * Render Guardian grid vertical rules. * * Left and right rules are always present. - * A centre rule can optionally be enabled. + * A centre rule can optionally be enabled, anchored to the nth + * child of the grid container as specified by the `plusChild` option * * Usage: * css([grid.container, grid.verticalRules()]) - * css([grid.container, grid.verticalRules({ centre: true })]) + * css([grid.container, grid.verticalRules({ plusChild: 3 })]) */ -const optionalCentreRule = `/* CENTRE RULE */ - & > *:first-child::before { - grid-column: centre-column-start; - transform: translateX(-${columnGap}); - ${fromBreakpoint.leftCol} { - transform: translateX(calc(-${columnGap} / 2)); - } + +// The centre rule is self-contained on the nth child element rather than on +// the grid container, so that `top: 0` aligns to that element's top edge. +// `bottom` uses a large negative value to extend the rule down to the +// container's bottom; ensure `overflow: hidden` is set on the container +const optionalCentreRule = ( + nth: number, + color?: string, +): string => `/* CENTRE RULE */ + & > *:nth-child(${nth}) { + position: relative; + + &::before { + position: absolute; + top: 0; + bottom: -9999px; + width: 1px; + background-color: ${color ?? palette('--article-border')}; + content: ''; + grid-column: centre-column-start; + transform: translateX(-${columnGap}); + + ${fromBreakpoint.leftCol} { + transform: translateX(calc(-${columnGap} / 2)); + } + } }`; -const verticalRules = (options: VerticalRuleOptions = {}): string => ` +const verticalRules = (options: VerticalRuleOptions = {}): string => { + const { plusChild, color } = options; + + return ` ${fromBreakpoint.tablet} { position: relative; &::before, - &::after - ${options.centre ? ', & > *:first-child::before' : ''} { + &::after { position: absolute; top: 0; bottom: 0; @@ -146,8 +168,9 @@ const verticalRules = (options: VerticalRuleOptions = {}): string => ` } } - ${options.centre ? optionalCentreRule : ''} -`; + ${plusChild !== undefined ? optionalCentreRule(plusChild, color) : ''} + }`; +}; // ----- API ----- // From b90f67d3e541ce6a6117aace1d1f77416d3f6410 Mon Sep 17 00:00:00 2001 From: Frederick O'Brien Date: Fri, 29 May 2026 17:14:09 +0100 Subject: [PATCH 2/2] Move gallery centre rule depending on breakpoint --- dotcom-rendering/src/components/GalleryImage.tsx | 6 +++++- dotcom-rendering/src/grid.ts | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dotcom-rendering/src/components/GalleryImage.tsx b/dotcom-rendering/src/components/GalleryImage.tsx index 5a37ed732c7..8907b414ac2 100644 --- a/dotcom-rendering/src/components/GalleryImage.tsx +++ b/dotcom-rendering/src/components/GalleryImage.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/react'; import { isUndefined } from '@guardian/libs'; -import { from, space, until } from '@guardian/source/foundations'; +import { between, from, space, until } from '@guardian/source/foundations'; import { grid } from '../grid'; import { type ArticleFormat } from '../lib/articleFormat'; import { getImage } from '../lib/image'; @@ -40,6 +40,10 @@ const styles = css` } } } + + ${between.desktop.and.leftCol} { + ${grid.verticalRules({ plusChild: 2 })} + } `; const galleryBodyImageStyles = css` diff --git a/dotcom-rendering/src/grid.ts b/dotcom-rendering/src/grid.ts index 4aec02a60c2..caaaf8f8c70 100644 --- a/dotcom-rendering/src/grid.ts +++ b/dotcom-rendering/src/grid.ts @@ -125,7 +125,7 @@ const optionalCentreRule = ( grid-column: centre-column-start; transform: translateX(-${columnGap}); - ${fromBreakpoint.leftCol} { + ${fromBreakpoint.desktop} { transform: translateX(calc(-${columnGap} / 2)); } }