<p>Resize the pen to see the card typography resize relative to the card&nbsp;size</p>
<div class="card-wrapper">
  <div class="card">
    <img src='https://images.unsplash.com/photo-1611916656173-875e4277bea6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MXwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHw&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <h3>A Super Wonderful Headline</h3>
    <p>Lorem ipsum sit dolor amit</p>
  </div>
  <div class="card">
    <img src='https://images.unsplash.com/photo-1611916656173-875e4277bea6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MXwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHw&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <h3>What a Fantabulous Title!</h3>
    <p>Lorem ipsum sit dolor amit</p>
  </div>
  <div class="card">
    <img src='https://images.unsplash.com/photo-1611916656173-875e4277bea6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MXwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHw&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <h3>Positively Terrific Title</h3>
    <p>Lorem ipsum sit dolor amit</p>
  </div>
</div>
/*
šŸŸ£ Learn more about what's going on here:

https://dev.to/5t3ph/experimental-solution-for-container-query-font-sizing-1b1o
*/

.card-wrapper {
  // baseline of max possible card width, really could be anything, even 0 since `clamp` prevents shrinking below our $font-min
  // We're going to use our midsize card, explained next
  --card-width: 544;
}

.card h3 {
  // Midtarget computed size: 28px
  --max: 2rem; // 32px
  --min: 1.25rem; // 20px

  // Where did 0.05 come from?
  // Our "midsize" ideal is 28px, and given a "midsize" card (the width of a card when 2-up on largest screen) the width (576) - padding (32) = 544.
  // 28/544 = 0.05 (rounded down for a nicer whole number)
  // Since `--card-width` is unitless, we need to assign a unit somewhere, hence the `0.05px`
  font-size: clamp(var(--min), calc(0.05px * var(--card-width)), var(--max));
}

/* Additional display styles */
* {
  box-sizing: border-box;
}

body {
  display: grid;
  place-content: center;
  justify-items: center;
  min-height: 100vh;
  margin: 0;
  padding-top: 1rem;
  padding-bottom: 1rem;
  line-height: 1.5;
  font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir,
    helvetica neue, helvetica, Ubuntu, roboto, noto, segoe ui, arial, sans-serif;
  color: #444;
  background-color: #e1faf1;
}

body > p {
  font-size: 2rem;
  text-align: center;
  max-width: 30ch;
  padding-left: 1rem;
  padding-right: 1rem;
  line-height: 1.3;
}

h3 {
  margin: 0;
}

.card-wrapper {
  max-width: 100vw;
  width: 120ch;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(30ch, 1fr));
  grid-gap: 1.5rem;
  padding-left: 1rem;
  padding-right: 1rem;
}

.card {
  background-color: #fff;
  border-radius: 0.5rem;
  box-shadow: 0.15rem 0.15rem 0.3rem -0.05rem rgba(0, 0, 0, 0.25);
  background-image: linear-gradient(
    var(--card-gradient),
    white max(10rem, 25vh)
  );

  img {
    border-radius: 0.5rem 0.5rem 0 0;
    width: 100%;
    aspect-ratio: 3/2;
    object-fit: cover;
    filter: grayscale(100);

    ~ * {
      margin-left: 1rem;
      margin-right: 1rem;
    }
  }
}
View Compiled
// @link https://codeburst.io/throttling-and-debouncing-in-javascript-b01cad5c8edf
const debounce = (callback, delay) => {
  let timeout;
  return () => {
    clearTimeout(timeout);
    timeout = setTimeout(callback, delay);
  };
};

// Find the first card in the set and get it's width
// to set the CSS custom property of `--card-width`
// enabling it to be used in our CSS `clamp` and value
const updateCardFontSize = () => {
  const card = document.querySelector(".card");
  const cardWrapper = document.querySelector(".card-wrapper");
  const cardWidth = card.clientWidth;

  cardWrapper.style.setProperty("--card-width", cardWidth);
};

updateCardFontSize();
window.addEventListener("resize", debounce(updateCardFontSize, 10));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.