Skip to content

Instantly share code, notes, and snippets.

@NetLancer
Last active December 28, 2023 08:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NetLancer/f95d5385b856f9b8e9f62e62602e8660 to your computer and use it in GitHub Desktop.
Save NetLancer/f95d5385b856f9b8e9f62e62602e8660 to your computer and use it in GitHub Desktop.
Responsive PW page via container width observe
<?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&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=2250&amp;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>
@NetLancer
Copy link
Author

NetLancer commented Dec 19, 2023

Attempt at setting cards with cards-container using css flexbox and some js (ResizeObserver API), +throttling no polyfilling. Width measure units - pixels

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment