GODRICH
#css-animation#button#loader#transition#scroll#ui#xu-huong-thiet-ke

9 mẫu press page design — dán vào landing

Press page design là bộ code gom sẵn từng khối của trang báo chí: press release, media kit, liên hệ người phụ trách.

Tự chạy · bấm ô để tới mục đó · cả 9 trong một zip

Chín mục xếp theo đúng trình tự nhà báo và nhà đầu tư lướt qua một press room. Đầu tiên là ấn tượng ban đầu (hero), kế đến tin mới nhất (danh sách press release), rồi tư liệu lấy về để viết bài (media kit), nơi đã đăng tải (thanh logo truyền thông), quy mô chứng minh bằng con số (điểm nhấn số liệu), liên hệ trực tiếp người phụ trách (thẻ liên hệ truyền thông), giọng nói thương hiệu (lời người sáng lập), chặng đường đã đi (timeline thành tựu), và cuối cùng là nhận tin cho lần sau (footer đăng ký). Ô mặt người phụ trách và ô logo nhà báo là placeholder hình khối vẽ bằng ba token mực·xanh·kem của site này, thay bằng ảnh thật thì bố cục và lề vẫn giữ nguyên. Ai đang gom press page design examples để dựng trang cho công ty mình thì cứ lấy đúng thứ tự này làm khung sườn.

01Hero truyền thông

Màn hình mở đầu của press room

Ba vòng tròn mờ phía sau sân khấu cứ trôi mãi, còn phía trước wordmark (placeholder hình khối)·tiêu đề lớn·phụ đề·hai nút CTA cùng nằm gọn trong một khung hình.

Hero phòng báo chí
Mở trong tab mới

01 · Hero phòng báo chí — Diện tích đo được 30.411% · khung hình chuyển động 18/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

transformopacityaria-pressed

Nút đăng ký đổi trạng thái thật

Mỗi lần nhấn nút đăng ký bên phải, trạng thái đăng ký và độ tô đặc của biểu tượng thay đổi theo.

.ph__orb--1 { animation: ph-float-a 2s ease-in-out infinite; }
@keyframes ph-float-a {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate($sp-10, -$sp-8) scale(1.5); }
}
.ph__sub-btn[aria-pressed="true"] {
  background: rgba(255, 247, 230, .12);
  border-color: $subject-cream;
}
.ph__sub-btn[aria-pressed="true"] .ph__sub-ic {
  opacity: 1;
  color: $color;
  transform: scale(1.15);
}

02Danh sách press release

Lọc biểu mẫu press release theo phân loại

Nhấp vào chip phân loại (tất cả·sản phẩm·hợp tác·giải thưởng) là những dòng sai loại gập lại thật, chỉ còn đúng phần được chọn.

Danh sách thông cáo báo chí
Mở trong tab mới

02 · Danh sách thông cáo báo chí — Diện tích đo được 0.271% · khung hình chuyển động 16/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

clickrl__filtersaria-pressed

Thanh accent quét tuần tự

Thanh accent bên trái từng dòng sáng dần theo thứ tự, tạo một chuyển động quét luôn lặp lại.

chips.forEach(function (chip) {
  chip.addEventListener('click', function () {
    root.classList.remove('is-demo');
    chips.forEach(function (c) { c.setAttribute('aria-pressed', 'false'); });
    chip.setAttribute('aria-pressed', 'true');
    var cat = chip.getAttribute('data-cat');
    rows.forEach(function (row) {
      var show = cat === 'all' || row.getAttribute('data-cat') === cat;
      row.classList.toggle('is-hidden', !show);
    });
  });
});

03Tải media kit

Chỉ nhận những file được chọn

Tích chọn logo pack·hướng dẫn thương hiệu·ảnh chụp sản phẩm thì nút tải file được chọn bật lên thật.

Tải media kit
Mở trong tab mới

03 · Tải media kit — Diện tích đo được 0.756% · khung hình chuyển động 22/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

checkboxstroke-dashoffsetclick

Nhấn xong đổi gì

Sau khi nhấn, từng file được chọn có biểu tượng check vẽ vào và số file đã nhận được thông báo bằng dòng chữ.

.mk::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0;
  height: 3px;
  background: $color;
  animation: mk-scan 2s $easing infinite;
}
.mk__done-ic {
  stroke: $color;
  stroke-width: 2.5;
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
  opacity: 0;
  transition: stroke-dashoffset $duration $easing, opacity $duration $easing;
}
.mk__row.is-done .mk__done-ic { stroke-dashoffset: 0; opacity: 1; }
.mk__btn:disabled { opacity: .4; cursor: not-allowed; }

04Thanh logo truyền thông

Tám biểu tượng chạy không đứt quãng

Tám dấu hiệu nhà báo vẽ bằng hình khối (không phải logo thật) nối thành một hàng và trôi đều không điểm gãy.

Dải logo báo chí
Mở trong tab mới

04 · Dải logo báo chí — Diện tích đo được 8.057% · khung hình chuyển động 23/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

translateX(-50%)animation-play-statepointerenter

Rê chuột là dừng ngay tại chỗ

Đưa con trỏ lên hoặc giữ nút bên cạnh thì dòng chảy đứng lại đúng vị trí đó.

// track không dùng gap — mỗi logo nhận margin-right riêng
.mb__track { display: flex; width: max-content; animation: mb-scroll $duration $easing infinite; }
.mb.is-paused .mb__track,
.mb__viewport:hover .mb__track { animation-play-state: paused; }
.mb__logo { flex: 0 0 auto; width: 64px; height: 32px; margin-right: $sp-6; }
@keyframes mb-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

05Điểm nhấn số liệu

Từ 0 đến giá trị đích

Ba con số lớn trên ba thẻ chạy từ 0 lên đúng giá trị đích thật (số bài báo·số đối tác truyền thông·lượt tải tích lũy) ngay khi mở trang, rồi dừng lại.

Bộ đếm số liệu
Mở trong tab mới

05 · Bộ đếm số liệu — Diện tích đo được 2.675% · khung hình chuyển động 21/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

requestAnimationFramecounteropacity

Thanh accent phía trên thẻ

Thanh accent trên đầu thẻ quét tuần tự và lặp lại liên tục.

.sc__card::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0;
  height: 3px;
  background: $color;
  animation: sc-pulse 2s $easing infinite;
}
.sc__card:nth-child(2)::before { animation-delay: 220ms; }
.sc__num {
  font-weight: 800; font-size: clamp(20px, 7vw, 28px); line-height: 1; font-family: inherit;
  color: $subject-cream;
  font-variant-numeric: tabular-nums;
}

06Thẻ liên hệ truyền thông

Email được sao chép thật

Dưới tên·chức danh người phụ trách truyền thông, nhấn nút email là địa chỉ vào clipboard thật.

Card liên hệ báo chí
Mở trong tab mới

06 · Card liên hệ báo chí — Diện tích đo được 3.774% · khung hình chuyển động 6/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

clipboardstroke-dashoffsetclick

Check biến mất sau 1,6 giây

Trên nút có biểu tượng check vẽ ra thoáng qua rồi biến mất sau 1,6 giây.

.mc__orb--1 { background: radial-gradient(circle, $subject-blue, transparent 68%); animation: mc-drift 8s ease-in-out infinite; }
.mc__orb--2 { background: radial-gradient(circle, $subject-ink, transparent 68%); animation: mc-drift 7s ease-in-out infinite reverse; }
.mc__avatar { background: $subject-ink; border-radius: 50%; }
.mc__copy-ic {
  stroke: $color;
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
  opacity: 0;
  transition: stroke-dashoffset $duration $easing, opacity $duration $easing;
}
.mc__copy.is-copied .mc__copy-ic { stroke-dashoffset: 0; opacity: 1; }

07Lời người sáng lập

Hai đoạn trích đổi chỗ qua hai chấm

Hai câu trích dẫn của người sáng lập đổi chỗ qua lại bằng hai nút chấm tròn.

Trích dẫn nhà sáng lập
Mở trong tab mới

07 · Trích dẫn nhà sáng lập — Diện tích đo được 0.366% · khung hình chuyển động 17/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

opacityclickaria-selected

Dấu ngoặc kép khẽ lay động

Nhấp một chấm là câu trích dẫn đó chuyển qua bằng hiệu ứng crossfade thật, còn dấu ngoặc kép lớn trang trí đung đưa dịu nhẹ.

dots.forEach(function (dot) {
  dot.addEventListener('click', function () {
    root.classList.remove('is-demo');
    var i = dot.getAttribute('data-i');
    dots.forEach(function (d) { d.classList.remove('is-active'); d.setAttribute('aria-selected', 'false'); });
    slides.forEach(function (s) { s.classList.remove('is-active'); });
    dot.classList.add('is-active'); dot.setAttribute('aria-selected', 'true');
    root.querySelector('.fq__slide[data-i="' + i + '"]').classList.add('is-active');
  });
});

08Timeline thành tựu

Tô đến đúng điểm được nhấp

Bốn mốc trên trục ngang (thành lập·Series A·mở rộng ra nước ngoài·1 triệu người dùng) nhấp vào đâu là thanh tiến trình tô scaleX đến đúng đấy.

Timeline cột mốc
Mở trong tab mới

08 · Timeline cột mốc — Diện tích đo được 0.438% · khung hình chuyển động 7/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

scaleXclickaria-current

Đoạn mô tả đổi theo

Đoạn mô tả phía trên cũng thay nội dung khớp với mốc thời gian đó.

.mt__fill {
  position: absolute; left: 0; right: 0; top: 4px;
  height: 3px;
  background: $color;
  transform: scaleX(.25);
  transform-origin: left;
  transition: transform $duration $easing;
}
.mt__stop[aria-current="step"] .mt__dot {
  background: $color;
  transform: scale(1.3);
  box-shadow: 0 0 0 4px rgba(47, 109, 246, .18);
}

09Footer truyền thông

Kiểm tra định dạng thật sự

Nhập email và nhấn đăng ký thì định dạng được kiểm tra thật: đúng thì vẽ check và hiện thông báo, sai thì ô nhập rung ngang vài nhịp.

Footer press room
Mở trong tab mới

09 · Footer press room — Diện tích đo được 0.578% · khung hình chuyển động 15/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

submitstroke-dashoffsetclick

Ba ô liên kết giữ nguyên vị trí

Ba ô liên kết phía dưới luôn đứng đúng chỗ.

.pf__input.is-shake { animation: pf-shake $dur-quick $ease-out; }
@keyframes pf-shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-5px); }
  75%      { transform: translateX(5px); }
}
.pf__submit { animation: pf-glow 2s ease-in-out infinite; }
@keyframes pf-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(47, 109, 246, .35); }
  50%      { box-shadow: 0 0 0 6px rgba(47, 109, 246, 0); }
}
.pf__form.is-done .pf__check { stroke-dashoffset: 0; opacity: 1; }

Mẫu trang báo chí dễ vỡ ở đâu — ba cái bẫy

Nền đặc che mất vòng tròn

Trong lúc làm chín mục này tôi vấp thật hai lần. Lần thứ nhất ở thẻ liên hệ truyền thông (06): lúc đầu sơn nền thẻ bằng màu kem đặc, thế nhưng vòng trôi phía sau nền có z-index:-1 nên bị che khuất hoàn toàn sau lớp nền đặc đó. Nhìn trên màn hình tưởng không có vấn đề gì, nhưng số pixel thật sự chuyển động gần như bằng không, gọi là animation còn thấy ngại.

Thiếu box-sizing thì sao

Bỏ nền thẻ đi cho vòng tròn lộ ra trên màu sân khấu là xong. Lần thứ hai nằm ở phần responsive của danh sách press release (02) và media kit (03): cả hai gập·mở dòng bằng max-height, mà không khai báo box-sizing thì padding cộng thẳng lên chiều cao đã đặt, chiều cao render thật vượt mức tính toán. Trên màn hình rộng 320px, chênh lệch ấy dồn lại và một thanh cuộn dọc xuất hiện âm thầm.

Khoảng cách marquee dùng margin-right

Thêm box-sizing: border-box và giảm padding cho màn hẹp là cả hai qua cổng. Thanh logo marquee (04) cũng có một bẫy quen thuộc: đặt khoảng cách giữa các mục bằng gap thì đường nối giữa hai dải (2N mục) thiếu đúng gap ÷ 2, nên mỗi vòng quay lại bị giật nhẹ một nhịp. Mẫu này cho khoảng cách bằng margin-right ngay từ đầu nên né được, và zip mở bằng mật khẩu 7a6mw6kt giữ nguyên đúng cách ấy. Tính cả hai cái bẫy trên, chín mục đang ở trạng thái mới nhất chạy chuẩn như bảng mô tả.

Khả năng tiếp cận

Khi giảm chuyển động thì trạng thái còn lại không

Cả chín mục tắt animation trang trí dưới prefers-reduced-motion: reduce nhưng giữ nguyên trạng thái — thanh tiến trình timeline dừng ở mức đã tô, danh sách đã lọc đứng gập sẵn, còn bộ đếm của điểm nhấn số liệu là thông tin nên giữ nguyên giá trị.

Điều khiển gốc và thông báo trạng thái

Ô chọn của media kit (03) là input[type="checkbox"] gốc nên Tab·Space vận hành được ngay; dòng kết quả của thẻ liên hệ (06) và footer (09) mang role="status" (aria-live) nên trình đọc màn hình đọc liền kết quả sao chép·gửi. Timeline (08) báo vị trí đang xem bằng aria-current="step", còn nút chấm của mục 07 truyền trạng thái qua role="group" và aria-selected.

Clipboard và phương án dự phòng

Phần sao chép clipboard (06) theo thông số MDN Clipboard API và rơi vào phương án textarea dự phòng trên môi trường không hỗ trợ. Các template tĩnh khác kiểu email·dashboard nằm trong danh sách chuyên mục template, và người vận hành blog này là ai thì trang giới thiệu đã ghi rõ.

FAQ — hỏi đáp nhanh

Mẫu press room có dùng logo hay ảnh thật được không?

Được, thiết kế sinh ra để làm điều đó — đó cũng là điểm phân biệt một bộ khối dùng lại được với một bản press page ui design chỉ đẹp trên ảnh chụp. Thay ô tròn avatar·ô logo nhà báo bằng file thật thì kích thước·canh lề vẫn giữ như cũ. Hình khối dùng đúng giá trị mực·xanh·kem của demo-tokens.scss, còn nền sân khấu (vàng·cam) là token khác hẳn nên hai bên không lẫn vào nhau.

Bản React khác bản CSS ở điểm nào?

Cách vận hành như nhau. Giá trị kiểu trạng thái lọc·ô chọn·trích dẫn đang mở quản lý bằng useState, còn ba biến (duration·easing·color) nhận qua props rồi truyền xuống biến CSS (--duration --easing --color). Bộ đếm của mục 05 chạy nguyên logic requestAnimationFrame đó bên trong useEffect.

Tải media kit có thật sự nhận file, hay chỉ trang trí?

Việc chọn ô, bật nút và dấu hoàn tất đều là thay đổi trạng thái thật. Chỉ có điều demo không gắn file thật, nên nhấn vào chưa bắt đầu tải xuống. Khi dùng thật, chỉ cần nối href thật vào từng dòng file là phần logic check·đếm phía sau tái sử dụng nguyên vẹn.

Nhập mật khẩu file nén

Mật khẩu nằm ngay trong bài viết này. Đọc tới đó bạn sẽ thấy.