15 CSS Testimonials & Reviews

Obsidian Editorial

A dark editorial spread with a featured testimonial spanning two rows and four secondary cards in a 3-column grid. Gold accent lines reveal on hover, large opacity-7% quote glyphs sit behind each quote, and pulsing "Verified" dots signal authenticity. Playfair Display for names + glyphs, Cormorant Garamond italic for the quotes — the magazine-cover treatment.

Pure CSS MIT licensed

Obsidian Editorial the 1st of 15 designs in the 15 CSS Testimonials & Reviews collection. The design is implemented in pure CSS — no JavaScript required. Copy the HTML and CSS panels below into your project. Because the demo is pure CSS, it works in any framework or templating engine you happen to use. The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.

Live preview

Open in playground

The code

<section class="tm-obs" aria-label="Client testimonials">
  <header class="tm-obs-head">Client Testimonials &middot; 2024</header>
  <div class="tm-obs-grid">

    <article class="tm-obs-card tm-obs-featured">
      <span class="tm-obs-accent" aria-hidden="true"></span>
      <span class="tm-obs-glyph" aria-hidden="true">&ldquo;</span>
      <div class="tm-obs-verified"><span class="tm-obs-vdot" aria-hidden="true"></span> Verified Purchase</div>
      <div class="tm-obs-stars" aria-label="5 out of 5 stars">
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
      </div>
      <blockquote class="tm-obs-quote">
        Working with them was unlike anything I'd experienced before. There's a rare quality in partners who can translate abstract vision into something that <em class="tm-obs-em">genuinely moves people</em>. Every deliverable exceeded what I thought was possible — not incrementally, but by an entirely different order of magnitude.
      </blockquote>
      <span class="tm-obs-rule" aria-hidden="true"></span>
      <figcaption class="tm-obs-author">
        <span class="tm-obs-avatar" aria-hidden="true">MV</span>
        <span class="tm-obs-meta">
          <cite class="tm-obs-name">Margaux Vellancourt</cite>
          <span class="tm-obs-role">Creative Director, Maison Cèdre</span>
        </span>
      </figcaption>
      <span class="tm-obs-source">G2 &middot; Verified</span>
    </article>

    <article class="tm-obs-card">
      <span class="tm-obs-accent" aria-hidden="true"></span>
      <span class="tm-obs-glyph" aria-hidden="true">&ldquo;</span>
      <div class="tm-obs-stars" aria-label="5 out of 5 stars">
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
      </div>
      <blockquote class="tm-obs-quote">
        The ROI was <em class="tm-obs-em">immediate and measurable</em>. Within three months our conversion rate doubled. I've never seen a team move that fast without sacrificing depth.
      </blockquote>
      <figcaption class="tm-obs-author">
        <span class="tm-obs-avatar" aria-hidden="true">JR</span>
        <span class="tm-obs-meta">
          <cite class="tm-obs-name">James Rothenberg</cite>
          <span class="tm-obs-role">VP Growth, Apex Capital</span>
        </span>
      </figcaption>
      <span class="tm-obs-source">Trustpilot</span>
    </article>

    <article class="tm-obs-card">
      <span class="tm-obs-accent" aria-hidden="true"></span>
      <span class="tm-obs-glyph" aria-hidden="true">&ldquo;</span>
      <div class="tm-obs-stars" aria-label="4.5 out of 5 stars">
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star tm-obs-star-half" aria-hidden="true"></span>
      </div>
      <blockquote class="tm-obs-quote">
        Elegance is hard to teach and <em class="tm-obs-em">even harder to find</em>. They brought both craft and instinct. Our brand finally feels like it belongs in the rooms we're trying to enter.
      </blockquote>
      <figcaption class="tm-obs-author">
        <span class="tm-obs-avatar" aria-hidden="true">SL</span>
        <span class="tm-obs-meta">
          <cite class="tm-obs-name">Simone Laurent</cite>
          <span class="tm-obs-role">Founder, Studio Onyx</span>
        </span>
      </figcaption>
      <span class="tm-obs-source">LinkedIn</span>
    </article>

    <article class="tm-obs-card">
      <span class="tm-obs-accent" aria-hidden="true"></span>
      <span class="tm-obs-glyph" aria-hidden="true">&ldquo;</span>
      <div class="tm-obs-stars" aria-label="5 out of 5 stars">
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
      </div>
      <blockquote class="tm-obs-quote">
        I handed them a problem without a brief and they returned a <em class="tm-obs-em">solution with a point of view</em>. That intellectual generosity is rare and worth every penny.
      </blockquote>
      <figcaption class="tm-obs-author">
        <span class="tm-obs-avatar" aria-hidden="true">AT</span>
        <span class="tm-obs-meta">
          <cite class="tm-obs-name">Alistair Thornwood</cite>
          <span class="tm-obs-role">Partner, Thornwood &amp; Co.</span>
        </span>
      </figcaption>
      <span class="tm-obs-source">Clutch</span>
    </article>

    <article class="tm-obs-card">
      <span class="tm-obs-accent" aria-hidden="true"></span>
      <span class="tm-obs-glyph" aria-hidden="true">&ldquo;</span>
      <div class="tm-obs-stars" aria-label="5 out of 5 stars">
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
        <span class="tm-obs-star" aria-hidden="true"></span>
      </div>
      <blockquote class="tm-obs-quote">
        Six-figure decision, zero regret. The project paid for itself in <em class="tm-obs-em">sixty-four days</em>. I'm not sure what else there is to say.
      </blockquote>
      <figcaption class="tm-obs-author">
        <span class="tm-obs-avatar" aria-hidden="true">NB</span>
        <span class="tm-obs-meta">
          <cite class="tm-obs-name">Nadia Blumenfeld</cite>
          <span class="tm-obs-role">CEO, Helix Ventures</span>
        </span>
      </figcaption>
      <span class="tm-obs-source">G2 &middot; Verified</span>
    </article>
  </div>
</section>
/* Obsidian Editorial — dark editorial spread. Self-contained: no body
   styles, no fixed positioning, all decoration lives inside .tm-obs.
   Each card is a real <article>, quote is a real <blockquote>, author
   is a real <figcaption> with <cite>. Hover reveals the gold accent
   line at the top of each card; the glyph quote-mark behind the quote
   gets slightly brighter. */
.tm-obs {
  --tm-obs-ink:       #0a0a0a;
  --tm-obs-paper:     #f5f0e8;
  --tm-obs-gold:      #b8962e;
  --tm-obs-gold-l:    #d4b253;
  --tm-obs-cream:     #ede8d8;
  --tm-obs-muted:     #5a5040;
  position: relative;
  padding: clamp(28px, 4vw, 56px) clamp(20px, 3vw, 44px);
  background: var(--tm-obs-ink);
  font-family: 'Cormorant Garamond', Georgia, serif;
  color: var(--tm-obs-cream);
  overflow: hidden;
  min-height: 520px;
}
/* Subtle film-grain overlay — pure SVG noise, no HTTP request. Adds
   tactile depth so the flat black surface reads as paper, not as a
   blank canvas. */
.tm-obs::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
  opacity: 0.4;
  pointer-events: none;
  z-index: 0;
}
.tm-obs-head {
  position: relative;
  z-index: 1;
  font-family: 'DM Mono', 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--tm-obs-gold);
  margin-bottom: 36px;
  display: flex;
  align-items: center;
  gap: 16px;
}
.tm-obs-head::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, var(--tm-obs-gold), transparent);
  max-width: 200px;
}
.tm-obs-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  grid-template-rows: auto auto;
  gap: 1px;
  background: #1a1510;
}
.tm-obs-card {
  background: var(--tm-obs-ink);
  padding: 32px 28px;
  position: relative;
  overflow: hidden;
  transition: background 0.5s;
  display: flex;
  flex-direction: column;
}
.tm-obs-card:hover { background: #0f0d08; }
.tm-obs-featured {
  grid-row: 1 / 3;
  background: #0d0b06;
  border-right: 1px solid #1a1510;
}
.tm-obs-glyph {
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 200px;
  line-height: 0.7;
  color: var(--tm-obs-gold);
  opacity: 0.08;
  position: absolute;
  top: 24px;
  left: 28px;
  pointer-events: none;
  user-select: none;
  transition: opacity 0.5s;
}
.tm-obs-card:hover .tm-obs-glyph { opacity: 0.14; }
.tm-obs-featured .tm-obs-glyph {
  font-size: 280px;
  opacity: 0.06;
  top: 16px;
}
.tm-obs-featured:hover .tm-obs-glyph { opacity: 0.1; }
.tm-obs-accent {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(to right, var(--tm-obs-gold), transparent);
  opacity: 0;
  transition: opacity 0.5s;
}
.tm-obs-card:hover .tm-obs-accent { opacity: 1; }
.tm-obs-featured .tm-obs-accent { opacity: 0.4; }
.tm-obs-featured:hover .tm-obs-accent { opacity: 1; }
.tm-obs-verified {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: 'DM Mono', 'JetBrains Mono', monospace;
  font-size: 8px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--tm-obs-gold);
  margin-bottom: 14px;
  position: relative;
  z-index: 1;
}
.tm-obs-vdot {
  width: 5px;
  height: 5px;
  background: var(--tm-obs-gold);
  border-radius: 50%;
  animation: tm-obs-pulse 2s infinite;
}
@keyframes tm-obs-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.5; transform: scale(0.7); }
}
.tm-obs-stars {
  display: flex;
  gap: 4px;
  margin-bottom: 20px;
  position: relative;
  z-index: 1;
}
.tm-obs-star {
  width: 10px;
  height: 10px;
  background: var(--tm-obs-gold);
  clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}
.tm-obs-star-half {
  background: linear-gradient(to right, var(--tm-obs-gold) 50%, #2a2418 50%);
}
.tm-obs-quote {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 300;
  color: var(--tm-obs-cream);
  line-height: 1.65;
  margin: 0 0 24px;
  font-size: 1.02rem;
  position: relative;
  z-index: 1;
  border: 0;
  padding: 0;
}
.tm-obs-featured .tm-obs-quote {
  font-size: 1.35rem;
  margin-bottom: 32px;
}
.tm-obs-em {
  color: var(--tm-obs-gold-l);
  font-style: normal;
  font-weight: 400;
}
.tm-obs-rule {
  display: block;
  width: 40px;
  height: 1px;
  background: var(--tm-obs-gold);
  margin: 20px 0;
  opacity: 0.5;
  position: relative;
  z-index: 1;
}
.tm-obs-author {
  display: flex;
  align-items: center;
  gap: 14px;
  position: relative;
  z-index: 1;
  margin-top: auto;
}
.tm-obs-avatar {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid var(--tm-obs-gold);
  background: #1a1510;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 13px;
  color: var(--tm-obs-gold);
  opacity: 0.85;
  flex-shrink: 0;
}
.tm-obs-featured .tm-obs-avatar {
  width: 52px;
  height: 52px;
}
.tm-obs-meta { display: flex; flex-direction: column; }
.tm-obs-name {
  font-family: 'Playfair Display', Georgia, serif;
  font-size: 13px;
  font-style: normal;
  color: var(--tm-obs-paper);
  letter-spacing: 0.05em;
  margin-bottom: 3px;
}
.tm-obs-role {
  font-family: 'DM Mono', 'JetBrains Mono', monospace;
  font-size: 9px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--tm-obs-muted);
}
.tm-obs-source {
  position: absolute;
  bottom: 16px;
  right: 16px;
  font-family: 'DM Mono', 'JetBrains Mono', monospace;
  font-size: 8px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--tm-obs-muted);
  border: 1px solid #2a2418;
  padding: 3px 7px;
}
/* Mobile fallback — collapse 3 cols to a single stack so cards stay
   readable. Featured stops spanning two rows. */
@media (max-width: 720px) {
  .tm-obs-grid { grid-template-columns: 1fr; }
  .tm-obs-featured { grid-row: auto; border-right: none; }
  .tm-obs-glyph,
  .tm-obs-featured .tm-obs-glyph { font-size: 120px; top: 12px; left: 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .tm-obs-vdot { animation: none; }
  .tm-obs-card { transition: none; }
}

Search CodeFronts

Loading…