Last active
December 28, 2023 08:41
-
-
Save NetLancer/f95d5385b856f9b8e9f62e62602e8660 to your computer and use it in GitHub Desktop.
Responsive PW page via container width observe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace ProcessWire; | |
/** | |
* Processwire CMS/CMF template file | |
* Attempt at responsive design via watching corresponding container element | |
* instead of relying on the whole document width | |
* Flexbox styling with some javascript sprinkling | |
* See coupla constants to modify (if needed): BASE_CARD_WIDTH, MAX_CARD_WIDTH | |
*/ | |
?> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<!-- document head tag --> | |
<style> | |
#content .cards_container { | |
display: flex; | |
/* justify-content:space-between; */ | |
flex-wrap:wrap; | |
margin:0 | |
padding: 1.5rem 0; | |
} | |
.card { | |
background:#fff; | |
margin-bottom:1.5rem; | |
flex:1 0 500px; | |
box-sizing:border-box; | |
margin:1rem .25em; | |
} | |
.card figure { | |
position:relative; | |
margin-bottom:0; | |
width:100%; | |
} | |
article.card:hover > figure img { box-shadow: 5px 10px 8px #888888; } | |
.card figure > figcaption { | |
width:inherit; | |
text-align:center; | |
position:absolute; | |
bottom:1.2em; | |
background-color:SlateGray; | |
color:#fff; | |
font-family:"Times New Roman", Times, serif; | |
font-style:italic; | |
letter-spacing:1px; | |
border-top:2px solid DimGray; | |
opacity:0; | |
transition:opacity 0.35s linear; | |
} | |
.card figure:hover > figcaption { opacity:0.8; } | |
.card a { text-decoration:none; } | |
.card a:hover { | |
box-shadow: 3px 3px 8px hsl(0, 0%, 80%); | |
} | |
.card_content { | |
padding:0.5em 0.75em 1.2em 0.75em; | |
background-color: #f5f5f5; | |
} | |
.card_content .card_header { | |
margin-top:0; margin-bottom:.5em; | |
font-weight:bold; | |
text-align:center; | |
} | |
.card_text { | |
/**Major Properties**/ | |
overflow:hidden; | |
line-height:1.5rem; | |
max-height:6rem; | |
-webkit-box-orient:vertical; | |
display:block; | |
display:-webkit-box; | |
overflow:hidden !important; | |
text-overflow:ellipsis; | |
-webkit-line-clamp:4; | |
} | |
.card_content p { font-size:86%; } | |
/* ////////// our workaround ////////// */ | |
section[data-col-num] > .card { flex-grow:0; flex-shrink:0; } | |
section[data-col-num='col_4'] > .card { flex-basis:24%; flex-basis:calc(25% - 1em); } | |
section[data-col-num='col_3'] > .card { flex-basis:32%; flex-basis:calc(33.3% - 1em); } | |
section[data-col-num='col_2'] > .card { flex-basis:48%; flex-basis:calc(50% - 1.25em); } | |
section[data-col-num='col_1'] > .card { flex-basis:94%; } | |
</style> | |
<!-- DOCUMENT BODY --> | |
<div id='content'> | |
echo "<section class='cards_container'>"; | |
foreach($stories as $key => $story) { | |
echo " | |
<article class='card'> | |
<figure> | |
<img src='https://images.unsplash.com/photo-1519681393784-d120267933ba?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2250&q=80' alt='Snowy Mountains' /> | |
<figcaption>Read Link below</figcaption> | |
</figure> | |
<div class='card_content'> | |
<a href='{$story->url}'> | |
<h2 class='card_header'>{$story->title}</h2> | |
<p class='card_text'>{$story->summary}</p> | |
</a> | |
</div> | |
</article> | |
";} | |
echo "</section>"; | |
<!-- probably render Pagination element --> | |
</div> | |
<!-- SIDEBAR SECTION --> | |
<!-- SITE FOOTER --> | |
<!-- Before closing body tag --> | |
<script> | |
// src: dev.to/shivamblog/day-4-throttling-debouncing-7dc | |
function throttle(func, delay = 250) { | |
let lastCall = 0; | |
return function() { | |
const now = new Date().getTime(); | |
if (now - lastCall < delay) return; | |
lastCall = now; | |
return func.apply(this, arguments); | |
}; | |
} | |
const container = document.getElementById('content'); | |
const cards_container = document.querySelector('#content .cards_container'); | |
const cards = document.getElementsByClassName('card'); | |
// modify as seen fit | |
const BASE_CARD_WIDTH = 264; | |
const MAX_CARD_WIDTH = 360; | |
const GAP_THRESHOLD = 32; | |
let colsNum = 1, gap = 1; // ..never mind | |
let card_width = cards[0].offsetWidth; | |
for (const card of cards) { card.style.maxWidth = MAX_CARD_WIDTH + 'px'; } | |
/////// Resizer API /////// | |
const resizeObserver = new ResizeObserver(throttle((entries) => { | |
const cnt_width = Math.floor(entries[0].contentRect.width); | |
// maximum 4 columns, otherwise touch css as well | |
colsNum = Math.max(1, Math.min(4, Math.floor(cnt_width / BASE_CARD_WIDTH))); | |
cards[0].offsetWidth; | |
card_width = cards[0].offsetWidth; | |
// free space between cards | |
gap = Math.floor(cnt_width - (card_width * colsNum) / (colsNum - 1)); | |
cards_container.style.justifyContent = colsNum > 1 ? (gap > GAP_THRESHOLD ? 'unset' : 'space-between') : 'center'; | |
let sizeNamed = 'col_' + colsNum; | |
cards_container.dataset.colNum = sizeNamed; | |
}, 200)); | |
resizeObserver.observe(container); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Attempt at setting cards with cards-container using css flexbox and some js (ResizeObserver API), +throttling no polyfilling. Width measure units - pixels