Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions src/core/caniuse.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,21 +179,22 @@ async function processJson(json, { feature }) {
]);
const toBrowserCell = browserCellRenderer(feature);
results.reduce(toBrowserCell, groups);
const out = [...groups]
const entries = [...groups]
.filter(([, arr]) => arr.length)
.map(
// A dl only permits dt/dd, optionally grouped in a div. The dt comes
// first for valid markup; the CSS puts the label back on the rule under
// the browsers, where it reads as a legend.
([key, arr]) =>
html`<div class="caniuse-group">
<div class="caniuse-browsers">${arr}</div>
<div class="caniuse-type"><span>${key}</div>
<dt class="caniuse-type"><span>${key}</span></dt>
<dd class="caniuse-browsers">${arr}</dd>
</div>`
);
out.push(
html`<a class="caniuse-cell" href="https://caniuse.com/${feature}"
return html`<dl class="caniuse-groups">${entries}</dl>
<a class="caniuse-more-info" href="https://caniuse.com/${feature}"
>More info</a
>`
);
return out;
>`;
}

/**
Expand Down
73 changes: 69 additions & 4 deletions src/styles/caniuse.css.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,64 @@ export default css`
column-gap: 2em;
}

/* The dl is a new wrapper around the groups, so it has to be transparent to
the flex row that used to hold them directly. */
.caniuse-groups {
display: flex;
flex: 1;
column-gap: 2em;
margin: 0;
}

/* Narrow screens: stack the groups full width so the pills wrap instead of
forming tall single-file columns, and give "More info" its own row.
767px matches the only other breakpoint in ReSpec (respec.css.js). */
@media (max-width: 767px) {
.caniuse-stats {
display: block;
}

.caniuse-groups {
flex-direction: column;
}

/* Space every group equally, including the first. Using padding rather than
row-gap avoids the second group getting gap plus padding while the first
gets padding alone. Generous, because each group's label hangs below its
own rule, and a tight gap reads as the label belonging to the group
beneath it. */
.caniuse-group {
padding-top: 1.5em;
}

.caniuse-more-info {
display: block;
text-align: right;
margin-top: 0.5em;
}
}

/* column-reverse, not column: a dl requires the dt before its dd, but the
label belongs visually below, straddling the rule under the browsers. */
.caniuse-group {
display: flex;
flex: 1;
flex-direction: column;
flex-direction: column-reverse;
justify-content: flex-end;
flex-basis: auto;
/* Establish a stacking context so the label can be lifted above the dd's
bottom border. Reversing the visual order does not reverse paint order:
the dd is a later sibling, so its border would paint over the label and
strike the text through. */
position: relative;
}

.caniuse-browsers {
display: flex;
align-items: baseline;
justify-content: space-between;
flex-wrap: wrap;
margin-top: .2em;
margin: .2em 0 0;
column-gap: .4em;
border-bottom: 1px solid #ccc;
row-gap: .4em;
Expand All @@ -37,10 +81,20 @@ export default css`
font-size: .8em;
margin-top: -.8em;
font-weight: bold;
/* Above the dd's border, so the label's background breaks the rule instead
of the rule striking through the text. */
position: relative;
z-index: 1;
}

/* The label punches a hole in the rule above it, so its background has to match
the page. This was var(--bg, white), but --bg is defined nowhere in ReSpec,
so it always resolved to literal white: a white patch on a dark page.
Canvas/CanvasText are system colours that follow the used color-scheme, so
this tracks both the OS preference and ReSpec's own dark toggle. */
.caniuse-type span {
background-color: var(--bg, white);
background-color: Canvas;
color: CanvasText;
padding: 0 0.4em;
}

Expand Down Expand Up @@ -83,7 +137,7 @@ img.caniuse-browser {
font-size: .9em;
}

.caniuse-stats a[href] {
.caniuse-more-info {
white-space: nowrap;
align-self: flex-end;
}
Expand Down Expand Up @@ -118,6 +172,17 @@ see https://github.com/Fyrd/caniuse/blob/master/CONTRIBUTING.md for stats */

/* handle case when printing */
@media print {
/* Browsers drop backgrounds when printing, so the label can no longer punch
a hole in the rule and the line would strike through the text. Drop the
rule instead and let the label sit under its group. */
.caniuse-browsers {
border-bottom: none;
}

.caniuse-type {
margin-top: 0;
}

.caniuse-cell.y::before {
content: "✔️";
padding: 0.5em;
Expand Down
30 changes: 28 additions & 2 deletions tests/spec/core/caniuse-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe("Core — Can I Use", () => {
const doc = await makeRSDoc(ops);
const stats = doc.querySelector(".caniuse-stats");
const cells = stats.querySelectorAll(".caniuse-cell");
expect(cells).toHaveSize(4);
expect(cells).toHaveSize(3);

// Check a cell
const [cell] = cells;
Expand Down Expand Up @@ -123,9 +123,13 @@ describe("Core — Can I Use", () => {
);

// More info link
const moreInfoLink = cells.item(3);
const moreInfoLink = stats.querySelector("a[href*='caniuse.com']");
expect(moreInfoLink.href).toBe("https://caniuse.com/FEATURE");
expect(moreInfoLink.textContent.trim()).toBe("More info");
// It must not carry .caniuse-cell: that sets color:#fff and a gradient from
// --caniuse-bg, which is only defined on the support-level classes, so the
// link rendered white on white.
expect(moreInfoLink.classList.contains("caniuse-cell")).toBeFalse();
});

it("removes irrelevant config for caniuse feature", async () => {
Expand Down Expand Up @@ -231,4 +235,26 @@ describe("Core — Can I Use", () => {
"mobile"
);
});

it("marks up the groups as a dl, with the More info link outside it", async () => {
const ops = makeStandardOps({
caniuse: {
feature: "FEATURE",
apiURL,
},
});
const doc = await makeRSDoc(ops);
const stats = doc.querySelector(".caniuse-stats");
const list = stats.querySelector("dl.caniuse-groups");
// A dl only allows dt/dd, optionally wrapped in a div.
expect(list.querySelectorAll(":scope > div.caniuse-group")).toHaveSize(2);
expect(
list.querySelectorAll(":scope > div > dt.caniuse-type:first-child")
).toHaveSize(2);
expect(
list.querySelectorAll(":scope > div > dd.caniuse-browsers:last-child")
).toHaveSize(2);
// So the link is a sibling of the list, not inside it.
expect(stats.querySelector("a[href]").parentElement).toBe(stats);
});
});