Skip to content

Commit 802d923

Browse files
authored
Merge pull request #1368 from makeabilitylab/1367-project-listing-mobile-overflow
fix(projects): stop project-listing grid overflowing on mobile (#1367)
2 parents 02909b0 + 7dfb573 commit 802d923

2 files changed

Lines changed: 61 additions & 20 deletions

File tree

website/static/website/css/project-listing.css

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -270,27 +270,29 @@
270270

271271
.project-grid {
272272
display: grid;
273-
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
273+
/*
274+
minmax(min(100%, 250px), 1fr): the min() guard caps each track at the
275+
container width, so a track can never overflow its parent (the classic
276+
CSS-grid mobile overflow bug). At ~250px the layout naturally yields a
277+
single column on phones, 2 on tablets, and 3+ on desktop. See the
278+
@media (max-width: 991px) block below, which also un-flexes .row-flex so
279+
the grid's parent reports a definite width (otherwise auto-fill collapses
280+
to one full-width column on tablets — the original off-screen-thumbnail bug).
281+
*/
282+
grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
274283
gap: var(--space-8);
275284
margin-top: var(--space-5);
276285
/* Removed min-height - let grid size naturally based on content */
277286
}
278287

279-
/* Responsive adjustments */
280-
@media (max-width: 576px) {
281-
.project-grid {
282-
grid-template-columns: 1fr;
283-
gap: var(--space-6);
284-
}
285-
}
286-
287288

288289
/* =============================================================================
289290
PROJECT CARD
290291
============================================================================= */
291292

292293
.project-card {
293294
position: relative;
295+
min-width: 0; /* Allow the card to shrink inside its grid track (prevents overflow) */
294296
transition: opacity 500ms ease; /* Match FADE_DURATION in JS */
295297
}
296298

@@ -319,13 +321,22 @@
319321
display: block;
320322
width: 100%;
321323
height: auto;
324+
/* Thumbnails are cropped to 500x300 (5:3); reserving the box prevents
325+
layout shift (CLS) while the image loads. object-fit guards any
326+
off-ratio source. */
327+
aspect-ratio: 5 / 3;
328+
object-fit: cover;
322329
border: 1px solid var(--color-border);
323330
border-radius: var(--border-radius-md);
324331
transition: transform var(--transition-normal);
325332
}
326333

327-
.project-image:hover .project-thumbnail {
328-
transform: scale(1.05);
334+
/* Only apply the hover zoom on devices with a real pointer; on touchscreens
335+
a :hover transform sticks awkwardly after a tap. */
336+
@media (hover: hover) {
337+
.project-image:hover .project-thumbnail {
338+
transform: scale(1.05);
339+
}
329340
}
330341

331342
/* Reduce motion for users who prefer it */
@@ -406,11 +417,29 @@
406417
RESPONSIVE ADJUSTMENTS
407418
============================================================================= */
408419

409-
/* Tablet and below: adjust grid gaps */
420+
/* Tablet and below: tighten the grid gap. (The flex->block switch that makes
421+
the grid go multi-column here lives in the FLEXBOX ROW HELPER section, which
422+
is mobile-first: block by default, flex only at >=992px.) */
410423
@media (max-width: 991px) {
411424
.project-grid {
412425
gap: var(--space-6);
413426
}
427+
428+
/* Narrow columns truncate titles aggressively; allow up to two lines.
429+
Overrides the shared .line-clamp-one-line utility for this page only. */
430+
.project-title a {
431+
white-space: normal;
432+
overflow: visible;
433+
}
434+
435+
.project-title .line-clamp-one-line {
436+
display: -webkit-box;
437+
-webkit-box-orient: vertical;
438+
-webkit-line-clamp: 2;
439+
line-clamp: 2;
440+
white-space: normal;
441+
overflow: hidden;
442+
}
414443
}
415444

416445
/* Phone: stack layout */
@@ -419,11 +448,11 @@
419448
flex-direction: column;
420449
align-items: flex-start;
421450
}
422-
451+
423452
.filter-mobile-container {
424453
width: 100%;
425454
}
426-
455+
427456
.filter-mobile-select {
428457
width: 100%;
429458
}
@@ -434,9 +463,19 @@
434463
FLEXBOX ROW HELPER
435464
============================================================================= */
436465

437-
.row-flex {
438-
display: flex;
439-
flex-wrap: wrap;
466+
/*
467+
Mobile-first: the row is a plain block by default so that .project-grid's
468+
parent (.col-md-10) has a DEFINITE width and the grid's auto-fill resolves
469+
to multiple columns. Only at >=992px — where the desktop filter sidebar
470+
appears — do we switch to flex to place the sidebar beside the content.
471+
(A flex parent gives the grid an indefinite width, which collapses auto-fill
472+
to a single oversized column — the original off-screen-thumbnail bug.)
473+
*/
474+
@media (min-width: 992px) {
475+
.row-flex {
476+
display: flex;
477+
flex-wrap: wrap;
478+
}
440479
}
441480

442481
/* Keep sidebar column aligned to top */

website/templates/snippets/display_project_snippet.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,11 @@
5959
<div class="project-image">
6060
<a href="{% url 'website:project' project.short_name %}"
6161
aria-label="View project: {{ project.name }}">
62-
<img class="project-thumbnail"
63-
src="{% thumbnail project.gallery_image project.get_thumbnail_size_as_str box=project.cropping crop=True upscale=True %}"
64-
alt="{{ project.get_thumbnail_alt_text }}">
62+
<img class="project-thumbnail"
63+
src="{% thumbnail project.gallery_image project.get_thumbnail_size_as_str box=project.cropping crop=True upscale=True %}"
64+
alt="{{ project.get_thumbnail_alt_text }}"
65+
loading="lazy"
66+
decoding="async">
6567

6668
{% if project.has_award %}
6769
<img class="project-award-banner"

0 commit comments

Comments
 (0)