6 CSS Minimalist UI Designs 03 / 06

Vera Lindstrom Portfolio

A brutalist-white minimalist portfolio UI for a Stockholm-based art director — a gallery-wall approach where the interface disappears so the creative work takes center stage.

Best fordesigner portfolios, photographer sites, architect studios, art director landing pages, creative agency homepages.

CSS + JS MIT licensed
Live Demo Open in tab
Open in playground

The code

<section class="mu-pf" aria-label="Vera Lindstrom creative portfolio demo">
  <div class="preview-img" data-mu-pf-preview aria-hidden="true">
    <svg data-mu-pf-preview-svg width="320" height="220" viewBox="0 0 320 220"></svg>
  </div>

  <header class="header">
    <div class="h-name">Vera Lindström</div>
    <nav class="h-nav">
      <a href="#">Work</a>
      <a href="#">About</a>
      <a href="#">Journal</a>
      <a href="#">Contact</a>
    </nav>
    <div class="h-status">
      <div class="status-dot" aria-hidden="true"></div>
      Available for projects
    </div>
  </header>

  <section class="hero">
    <div class="hero-index" aria-hidden="true">V</div>
    <div class="hero-text">
      <h1 class="hero-title">
        Visual<br><em>Architect</em><br>&amp; Director
      </h1>
      <div class="hero-meta">
        <div class="hero-role">Art Direction · Branding · UI</div>
        <p class="hero-desc">Building brand identities and digital experiences that earn their silence. Stockholm-based, globally engaged.</p>
      </div>
    </div>
    <div class="hero-scroll-indicator" aria-hidden="true">
      <div class="scroll-v-line"></div>
      <div class="scroll-v-txt">Scroll</div>
    </div>
  </section>

  <section class="work-section">
    <div class="section-rule">
      <span class="rule-num">01</span>
      <div class="rule-line"></div>
      <span class="rule-label">Selected Work</span>
    </div>
    <div class="project-list">
      <div class="project-item" data-color="#1a1714" data-color2="#3a3028" data-accent="#c8ff00">
        <div class="project-num">001</div>
        <div class="project-info">
          <div class="project-title">Maison Collective</div>
          <div class="project-tags">
            <span class="tag">Brand Identity</span>
            <span class="tag">·</span>
            <span class="tag">Art Direction</span>
          </div>
        </div>
        <div class="project-right">
          <span class="project-year">2025</span>
          <div class="project-arrow">→</div>
        </div>
      </div>
      <div class="project-item" data-color="#d4c4a8" data-color2="#b8a080" data-accent="#8a6040">
        <div class="project-num">002</div>
        <div class="project-info">
          <div class="project-title">Aether Digital</div>
          <div class="project-tags">
            <span class="tag">Product UI</span>
            <span class="tag">·</span>
            <span class="tag">Design System</span>
          </div>
        </div>
        <div class="project-right">
          <span class="project-year">2025</span>
          <div class="project-arrow">→</div>
        </div>
      </div>
      <div class="project-item" data-color="#2c4a3e" data-color2="#1a3028" data-accent="#a8d4b8">
        <div class="project-num">003</div>
        <div class="project-info">
          <div class="project-title"><em>Forma</em> Architecture</div>
          <div class="project-tags">
            <span class="tag">Photography</span>
            <span class="tag">·</span>
            <span class="tag">Editorial</span>
          </div>
        </div>
        <div class="project-right">
          <span class="project-year">2024</span>
          <div class="project-arrow">→</div>
        </div>
      </div>
      <div class="project-item" data-color="#8b6a3a" data-color2="#6a4a20" data-accent="#f0c880">
        <div class="project-num">004</div>
        <div class="project-info">
          <div class="project-title">Norde Finance</div>
          <div class="project-tags">
            <span class="tag">Motion</span>
            <span class="tag">·</span>
            <span class="tag">Campaign</span>
          </div>
        </div>
        <div class="project-right">
          <span class="project-year">2024</span>
          <div class="project-arrow">→</div>
        </div>
      </div>
      <div class="project-item" data-color="#4a3858" data-color2="#2a1838" data-accent="#d4a8f0">
        <div class="project-num">005</div>
        <div class="project-info">
          <div class="project-title">Lune Editorial</div>
          <div class="project-tags">
            <span class="tag">Publication</span>
            <span class="tag">·</span>
            <span class="tag">Typography</span>
          </div>
        </div>
        <div class="project-right">
          <span class="project-year">2024</span>
          <div class="project-arrow">→</div>
        </div>
      </div>
    </div>
  </section>

  <div class="about-strip">
    <div class="about-left">
      <div class="about-eyebrow">About the Practice</div>
      <h2 class="about-title">Design that<br>trusts the <em>void</em></h2>
      <p class="about-body">With fifteen years across Stockholm, London, and Tokyo, I've learned that the most memorable work is often the most restrained. I collaborate with founders, cultural institutions, and agencies to craft visual systems that hold their integrity across every surface.</p>
    </div>
    <div class="about-right">
      <div class="about-eyebrow">Disciplines</div>
      <div class="services-list">
        <div class="service-item"><span class="svc-num">—</span><span class="svc-name">Brand Identity &amp; Systems</span><span class="svc-type">Strategy · Visual</span></div>
        <div class="service-item"><span class="svc-num">—</span><span class="svc-name">Digital Product Design</span><span class="svc-type">UI · UX · Prototyping</span></div>
        <div class="service-item"><span class="svc-num">—</span><span class="svc-name">Art Direction</span><span class="svc-type">Photo · Film · Print</span></div>
        <div class="service-item"><span class="svc-num">—</span><span class="svc-name">Editorial Design</span><span class="svc-type">Books · Magazines</span></div>
        <div class="service-item"><span class="svc-num">—</span><span class="svc-name">Motion &amp; Campaign</span><span class="svc-type">Digital · Out-of-home</span></div>
      </div>
    </div>
  </div>

  <div class="contact-section">
    <div class="contact-label">Start a conversation</div>
    <a class="contact-email" href="#">[email protected]</a>
    <div class="contact-links">
      <a class="contact-link" href="#">Instagram</a>
      <a class="contact-link" href="#">LinkedIn</a>
      <a class="contact-link" href="#">Are.na</a>
      <a class="contact-link" href="#">Readcv</a>
    </div>
  </div>

  <footer class="footer">
    <span>© 2025 Vera Lindström Studio</span>
    <span>Stockholm · SE</span>
    <span>Currently: Available Q3 2025</span>
  </footer>
</section>
/* ─── 03 Vera Lindström — minimalist creative portfolio UI ─────── */
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400;1,700&family=IBM+Plex+Sans:wght@300;400&display=swap');

.mu-pf {
  --mu-pf-white: #fafafa;
  --mu-pf-off: #f2f0ec;
  --mu-pf-ink: #0f0f0f;
  --mu-pf-mid: #888;
  --mu-pf-light: #ccc;
  --mu-pf-rule: #e8e4de;
  --mu-pf-serif: 'Playfair Display', serif;
  --mu-pf-sans: 'IBM Plex Sans', sans-serif;

  position: relative;
  width: 100%;
  min-height: 1400px;
  background: var(--mu-pf-white);
  color: var(--mu-pf-ink);
  font-family: var(--mu-pf-sans);
  overflow-x: hidden;
  box-sizing: border-box;
}
.mu-pf *, .mu-pf *::before, .mu-pf *::after { box-sizing: border-box; margin: 0; padding: 0; }

.mu-pf .header { position: sticky; top: 0; z-index: 10; background: var(--mu-pf-white); display: flex; align-items: center; justify-content: space-between; padding: 28px 56px; }
.mu-pf .h-name { font-family: var(--mu-pf-serif); font-size: 18px; font-weight: 400; letter-spacing: 0.02em; }
.mu-pf .h-nav { display: flex; gap: 36px; }
.mu-pf .h-nav a { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--mu-pf-mid); text-decoration: none; transition: color 0.2s; }
.mu-pf .h-nav a:hover { color: var(--mu-pf-ink); }
.mu-pf .h-status { font-size: 11px; letter-spacing: 0.12em; color: var(--mu-pf-mid); display: flex; align-items: center; gap: 8px; }
.mu-pf .status-dot { width: 6px; height: 6px; border-radius: 50%; background: #4caf50; animation: mu-pf-blink 2s infinite; }
@keyframes mu-pf-blink { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }

.mu-pf .hero { min-height: 540px; display: flex; flex-direction: column; justify-content: flex-end; padding: 0 56px 64px; position: relative; }
.mu-pf .hero-index { position: absolute; top: 50%; left: 56px; transform: translateY(-50%); font-family: var(--mu-pf-serif); font-size: clamp(160px,18vw,260px); font-weight: 900; color: var(--mu-pf-off); line-height: 1; letter-spacing: -0.05em; user-select: none; pointer-events: none; }
.mu-pf .hero-text { position: relative; z-index: 2; display: grid; grid-template-columns: 1fr auto; align-items: flex-end; gap: 64px; padding-top: 180px; }
.mu-pf .hero-title { font-family: var(--mu-pf-serif); font-size: clamp(52px,7vw,96px); font-weight: 400; line-height: 1.05; letter-spacing: -0.02em; animation: mu-pf-fadein 1s ease 0.2s both; }
.mu-pf .hero-title em { font-style: italic; font-weight: 400; }
.mu-pf .hero-meta { text-align: right; max-width: 260px; animation: mu-pf-fadein 1s ease 0.4s both; }
.mu-pf .hero-role { font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--mu-pf-mid); margin-bottom: 14px; }
.mu-pf .hero-desc { font-size: 13px; line-height: 1.8; color: var(--mu-pf-mid); font-weight: 300; }
.mu-pf .hero-scroll-indicator { display: flex; flex-direction: column; align-items: center; gap: 8px; position: absolute; right: 56px; bottom: 64px; }
.mu-pf .scroll-v-line { width: 1px; height: 60px; background: var(--mu-pf-light); animation: mu-pf-scrollline 2s ease infinite; }
@keyframes mu-pf-scrollline { 0% { transform: scaleY(0); transform-origin: top; } 50% { transform: scaleY(1); transform-origin: top; } 51% { transform: scaleY(1); transform-origin: bottom; } 100% { transform: scaleY(0); transform-origin: bottom; } }
.mu-pf .scroll-v-txt { font-size: 9px; letter-spacing: 0.2em; color: var(--mu-pf-light); text-transform: uppercase; writing-mode: vertical-rl; transform: rotate(180deg); }
@keyframes mu-pf-fadein { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }

.mu-pf .work-section { padding: 0 56px 120px; }
.mu-pf .section-rule { display: flex; align-items: center; gap: 24px; padding: 64px 0 48px; }
.mu-pf .rule-num { font-family: var(--mu-pf-serif); font-size: 11px; color: var(--mu-pf-mid); font-style: italic; }
.mu-pf .rule-line { flex: 1; height: 1px; background: var(--mu-pf-light); }
.mu-pf .rule-label { font-size: 10px; letter-spacing: 0.25em; text-transform: uppercase; color: var(--mu-pf-mid); }

.mu-pf .project-list { display: flex; flex-direction: column; gap: 0; }
.mu-pf .project-item { display: grid; grid-template-columns: 80px 1fr auto; align-items: center; gap: 32px; padding: 28px 0; border-bottom: 1px solid var(--mu-pf-rule); cursor: pointer; position: relative; overflow: hidden; transition: padding 0.3s ease; }
.mu-pf .project-item:first-child { border-top: 1px solid var(--mu-pf-rule); }
.mu-pf .project-item::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--mu-pf-off); z-index: 0; transition: width 0.4s cubic-bezier(0.23,1,0.32,1); }
.mu-pf .project-item:hover::before { width: 100%; }
.mu-pf .project-item:hover { padding-left: 24px; }
.mu-pf .project-item:hover .project-title { letter-spacing: 0.01em; }
.mu-pf .project-num { font-family: var(--mu-pf-serif); font-size: 13px; color: var(--mu-pf-light); font-style: italic; position: relative; z-index: 1; }
.mu-pf .project-info { position: relative; z-index: 1; }
.mu-pf .project-title { font-family: var(--mu-pf-serif); font-size: clamp(24px,3.5vw,42px); font-weight: 400; line-height: 1.1; transition: letter-spacing 0.3s; }
.mu-pf .project-tags { display: flex; gap: 12px; margin-top: 6px; }
.mu-pf .tag { font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--mu-pf-mid); }
.mu-pf .project-right { display: flex; align-items: center; gap: 32px; position: relative; z-index: 1; }
.mu-pf .project-year { font-size: 12px; color: var(--mu-pf-mid); font-family: var(--mu-pf-sans); }
.mu-pf .project-arrow { width: 44px; height: 44px; border: 1px solid var(--mu-pf-light); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 16px; color: var(--mu-pf-mid); transition: all 0.3s; }
.mu-pf .project-item:hover .project-arrow { background: var(--mu-pf-ink); border-color: var(--mu-pf-ink); color: var(--mu-pf-white); transform: rotate(45deg); }

/* Hover SVG preview — positioned absolute inside the wrapper, follows
   the mouse via offsetX/offsetY computed against the wrapper. */
.mu-pf .preview-img { position: absolute; pointer-events: none; z-index: 50; width: 320px; height: 220px; opacity: 0; transform: translateY(10px) rotate(-2deg); transition: opacity 0.3s, transform 0.3s; border-radius: 2px; overflow: hidden; top: 0; left: 0; }
.mu-pf .preview-img.visible { opacity: 1; transform: translateY(0) rotate(-1deg); }

.mu-pf .about-strip { display: grid; grid-template-columns: 1fr 1fr; gap: 0; margin: 0 56px; border-top: 1px solid var(--mu-pf-rule); padding: 80px 0; }
.mu-pf .about-left { padding-right: 80px; border-right: 1px solid var(--mu-pf-rule); }
.mu-pf .about-right { padding-left: 80px; }
.mu-pf .about-eyebrow { font-size: 10px; letter-spacing: 0.25em; text-transform: uppercase; color: var(--mu-pf-mid); margin-bottom: 20px; }
.mu-pf .about-title { font-family: var(--mu-pf-serif); font-size: clamp(32px,4vw,52px); font-weight: 400; line-height: 1.15; margin-bottom: 24px; }
.mu-pf .about-title em { font-style: italic; }
.mu-pf .about-body { font-size: 13.5px; line-height: 1.9; color: var(--mu-pf-mid); font-weight: 300; max-width: 400px; }
.mu-pf .services-list { display: flex; flex-direction: column; gap: 16px; }
.mu-pf .service-item { display: flex; align-items: baseline; gap: 16px; padding-bottom: 16px; border-bottom: 1px solid #ece8e2; }
.mu-pf .service-item:last-child { border-bottom: none; padding-bottom: 0; }
.mu-pf .svc-num { font-family: var(--mu-pf-serif); font-size: 11px; color: var(--mu-pf-light); font-style: italic; min-width: 24px; }
.mu-pf .svc-name { font-size: 14px; font-weight: 400; }
.mu-pf .svc-type { margin-left: auto; font-size: 10px; letter-spacing: 0.1em; color: var(--mu-pf-mid); }

.mu-pf .contact-section { padding: 80px 56px; text-align: center; border-top: 1px solid var(--mu-pf-rule); }
.mu-pf .contact-label { font-size: 10px; letter-spacing: 0.3em; text-transform: uppercase; color: var(--mu-pf-mid); margin-bottom: 24px; }
.mu-pf .contact-email { font-family: var(--mu-pf-serif); font-size: clamp(36px,6vw,80px); font-weight: 400; font-style: italic; text-decoration: none; color: var(--mu-pf-ink); display: inline-block; transition: letter-spacing 0.4s; }
.mu-pf .contact-email:hover { letter-spacing: 0.02em; }
.mu-pf .contact-links { display: flex; justify-content: center; gap: 40px; margin-top: 40px; }
.mu-pf .contact-link { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--mu-pf-mid); text-decoration: none; transition: color 0.2s; }
.mu-pf .contact-link:hover { color: var(--mu-pf-ink); }

.mu-pf .footer { display: flex; justify-content: space-between; align-items: center; padding: 28px 56px; border-top: 1px solid var(--mu-pf-rule); }
.mu-pf .footer span { font-size: 11px; color: var(--mu-pf-mid); }

@media (max-width: 760px) {
  .mu-pf .header, .mu-pf .hero, .mu-pf .work-section, .mu-pf .contact-section, .mu-pf .footer { padding-left: 24px; padding-right: 24px; }
  .mu-pf .h-nav { display: none; }
  .mu-pf .hero-text { grid-template-columns: 1fr; gap: 32px; }
  .mu-pf .hero-meta { text-align: left; }
  .mu-pf .hero-scroll-indicator { display: none; }
  .mu-pf .about-strip { grid-template-columns: 1fr; margin: 0 24px; }
  .mu-pf .about-left { padding-right: 0; border-right: none; border-bottom: 1px solid var(--mu-pf-rule); padding-bottom: 48px; margin-bottom: 48px; }
  .mu-pf .about-right { padding-left: 0; }
  .mu-pf .footer { flex-direction: column; gap: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .mu-pf .status-dot, .mu-pf .scroll-v-line, .mu-pf .hero-title, .mu-pf .hero-meta { animation: none !important; }
  .mu-pf .project-item, .mu-pf .project-arrow, .mu-pf .preview-img { transition: none !important; }
}
(() => {
  // Scoped portfolio interactions. Drops the source mock's full-viewport
  // mix-blend-mode cursor (which would look broken inside an embedded
  // card) and keeps the hover-triggered SVG project preview that's the
  // actual differentiator. The preview is positioned via offsetX/offsetY
  // against the wrapper element so two demos can coexist on a page.
  const root = document.querySelector('.mu-pf');
  if (!root) return;
  const preview = root.querySelector('[data-mu-pf-preview]');
  const previewSvg = root.querySelector('[data-mu-pf-preview-svg]');
  if (!preview || !previewSvg) return;

  // Mouse position relative to the wrapper (not viewport), so the preview
  // floats correctly regardless of scroll position.
  root.addEventListener('mousemove', (e) => {
    const r = root.getBoundingClientRect();
    const x = e.clientX - r.left;
    const y = e.clientY - r.top;
    preview.style.left = (x + 24) + 'px';
    preview.style.top = (y - 100) + 'px';
  });

  const items = root.querySelectorAll('.project-item');
  items.forEach((item, i) => {
    item.addEventListener('mouseenter', () => {
      preview.classList.add('visible');
      const c1 = item.dataset.color || '#1a1714';
      const c2 = item.dataset.color2 || '#3a3028';
      const c3 = item.dataset.accent || '#c8ff00';
      previewSvg.innerHTML =
        '<defs>' +
          '<linearGradient id="mu-pf-pg' + i + '" x1="0%" y1="0%" x2="100%" y2="100%">' +
            '<stop offset="0%" style="stop-color:' + c1 + '"/>' +
            '<stop offset="100%" style="stop-color:' + c2 + '"/>' +
          '</linearGradient>' +
        '</defs>' +
        '<rect width="320" height="220" fill="url(#mu-pf-pg' + i + ')"/>' +
        '<line x1="0" y1="40" x2="320" y2="40" stroke="' + c3 + '" stroke-width="0.5" opacity="0.3"/>' +
        '<line x1="0" y1="180" x2="320" y2="180" stroke="' + c3 + '" stroke-width="0.5" opacity="0.3"/>' +
        '<text x="160" y="125" text-anchor="middle" font-family="\'Playfair Display\',serif" font-size="14" fill="' + c3 + '" opacity="0.5" letter-spacing="8">' + String(i + 1).padStart(3, '0') + '</text>' +
        '<circle cx="280" cy="40" r="20" fill="none" stroke="' + c3 + '" stroke-width="0.5" opacity="0.3"/>';
    });
    item.addEventListener('mouseleave', () => {
      preview.classList.remove('visible');
    });
  });
})();

Search CodeFronts

Loading…