원클릭으로
wp-responsive
Responsive design patterns — mobile-first breakpoints, fluid typography, responsive images, touch targets
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Responsive design patterns — mobile-first breakpoints, fluid typography, responsive images, touch targets
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
WordPress legacy theme best practices — proper enqueueing, escaping, hooks, security, and performance
Rank Math SEO configuration reference, schema JSON-LD templates, meta patterns, and SEO seeding commands
Audit criteria, severity definitions, report JSON schema, and quality thresholds for wp-audit agents
WP-CLI-first principle — use WP-CLI instead of generating PHP code whenever possible, with command reference, ACF seeding patterns, and environment-aware execution
Environment detection, configuration, and WP-CLI wrapper selection for local WordPress development
Demo HTML creation methodology — single-file demos with section comments for 1:1 WordPress conversion
| name | wp-responsive |
| description | Responsive design patterns — mobile-first breakpoints, fluid typography, responsive images, touch targets |
| user-invocable | false |
This skill defines the responsive design system used across all themes and demos. It uses mobile-first CSS with min-width media queries, fluid typography, and responsive image techniques.
All styles are written mobile-first. Base styles target the smallest screens, and min-width media queries progressively enhance for larger viewports.
| Name | Min-Width | Target Devices |
|---|---|---|
| Base | (no query) | All phones (320px+) |
| Small | 576px | Large phones, small tablets |
| Tablet | 768px | Tablets (portrait and landscape) |
| Desktop | 1024px | Desktops, laptops |
| Large | 1200px | Large desktops |
| Extra Large | 1440px | Ultra-wide screens |
/* Base: mobile-first (no media query) */
.services__grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-lg);
}
/* Small (576px+): 2 columns */
@media (min-width: 576px) {
.services__grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* Tablet (768px+): still 2 columns, wider gap */
@media (min-width: 768px) {
.services__grid {
gap: var(--spacing-xl);
}
}
/* Desktop (1024px+): 3 columns */
@media (min-width: 1024px) {
.services__grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* Large (1200px+): wider gap */
@media (min-width: 1200px) {
.services__grid {
gap: var(--spacing-2xl);
}
}
min-width, Never max-widthUse min-width queries exclusively. This enforces mobile-first thinking -- you start with the constrained layout and add complexity as space increases.
/* CORRECT: mobile-first with min-width */
@media (min-width: 768px) { ... }
/* WRONG: desktop-first with max-width */
@media (max-width: 767px) { ... }
The only exception to the max-width rule is for the hamburger/mobile menu toggle (see Navigation section below), where max-width can be used to hide desktop nav on mobile. Even then, prefer showing/hiding with min-width when possible.
The container stretches to fill the viewport on small screens and caps at the design system maximum on large screens.
.container {
width: 100%;
max-width: var(--container-max); /* 1280px */
margin-left: auto;
margin-right: auto;
padding-left: var(--spacing-md); /* 16px */
padding-right: var(--spacing-md);
}
@media (min-width: 768px) {
.container {
padding-left: var(--spacing-xl); /* 32px */
padding-right: var(--spacing-xl);
}
}
@media (min-width: 1024px) {
.container {
padding-left: var(--spacing-2xl); /* 48px */
padding-right: var(--spacing-2xl);
}
}
<header class="header">
<div class="container">
<div class="header__inner">
<a href="/" class="header__logo">
<img src="logo.svg" alt="Site Name">
</a>
<!-- Desktop navigation -->
<nav class="header__nav" id="main-nav">
<a href="#" class="nav__link nav__link--active">Home</a>
<a href="#services" class="nav__link">Services</a>
<a href="/pricing" class="nav__link">Pricing</a>
<a href="#contact" class="nav__link">Contact</a>
</nav>
<!-- CTA button (visible on desktop) -->
<a href="#contact" class="btn btn--primary header__cta">Get Started</a>
<!-- Hamburger button (visible on mobile) -->
<button class="header__hamburger" aria-label="Toggle menu" aria-expanded="false">
<span></span>
<span></span>
<span></span>
</button>
</div>
</div>
<!-- Mobile menu overlay -->
<div class="mobile-menu" id="mobile-menu" aria-hidden="true">
<nav class="mobile-menu__nav">
<a href="#" class="mobile-menu__link">Home</a>
<a href="#services" class="mobile-menu__link">Services</a>
<a href="/pricing" class="mobile-menu__link">Pricing</a>
<a href="#contact" class="mobile-menu__link">Contact</a>
</nav>
<a href="#contact" class="btn btn--primary mobile-menu__cta">Get Started</a>
</div>
</header>
/* Mobile: hamburger visible, desktop nav hidden */
.header__nav,
.header__cta {
display: none;
}
.header__hamburger {
display: flex;
flex-direction: column;
justify-content: center;
gap: 5px;
width: 44px;
height: 44px;
background: none;
border: none;
cursor: pointer;
padding: var(--spacing-sm);
}
.header__hamburger span {
display: block;
width: 24px;
height: 2px;
background: var(--color-text);
transition: var(--transition-base);
}
/* Mobile menu (hidden by default) */
.mobile-menu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: var(--color-background);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--spacing-xl);
transform: translateX(100%);
transition: transform 0.3s ease;
z-index: 999;
}
.mobile-menu.is-open {
transform: translateX(0);
}
.mobile-menu__link {
font-size: var(--font-size-xl);
font-weight: var(--font-weight-medium);
padding: var(--spacing-md);
}
/* Desktop (1024px+): show nav, hide hamburger */
@media (min-width: 1024px) {
.header__nav {
display: flex;
align-items: center;
gap: var(--spacing-lg);
}
.header__cta {
display: inline-flex;
}
.header__hamburger {
display: none;
}
.mobile-menu {
display: none;
}
}
const hamburger = document.querySelector('.header__hamburger');
const mobileMenu = document.getElementById('mobile-menu');
if (hamburger && mobileMenu) {
hamburger.addEventListener('click', () => {
const isOpen = mobileMenu.classList.toggle('is-open');
hamburger.setAttribute('aria-expanded', isOpen);
mobileMenu.setAttribute('aria-hidden', !isOpen);
document.body.style.overflow = isOpen ? 'hidden' : '';
});
}
/* Mobile: single column */
.features__grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-lg);
}
/* Tablet: 2 columns */
@media (min-width: 768px) {
.features__grid {
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-xl);
}
}
/* Desktop: 3 columns */
@media (min-width: 1024px) {
.features__grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* Large: 4 columns */
@media (min-width: 1200px) {
.features__grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* Mobile: stacked vertically */
.hero__inner {
display: flex;
flex-direction: column;
gap: var(--spacing-xl);
}
/* Desktop: side by side */
@media (min-width: 1024px) {
.hero__inner {
flex-direction: row;
align-items: center;
}
.hero__content {
flex: 1;
}
.hero__image {
flex: 1;
}
}
.hero__inner {
display: flex;
flex-direction: column-reverse; /* image first on mobile */
gap: var(--spacing-xl);
}
@media (min-width: 1024px) {
.hero__inner {
flex-direction: row; /* content left, image right on desktop */
}
}
Use clamp() for headings and large text to smoothly scale between viewport sizes without media query jumps.
font-size: clamp(<minimum>, <preferred>, <maximum>);
/* Hero title: 2rem at minimum, scales with viewport, caps at 4rem */
.hero__title {
font-size: clamp(2rem, 5vw, 4rem);
}
/* Section title: 1.5rem to 2.5rem */
.section__title {
font-size: clamp(1.5rem, 3vw, 2.5rem);
}
/* Body text: stays readable at all sizes */
.hero__subtitle {
font-size: clamp(1rem, 2.5vw, 1.25rem);
}
/* Large display text */
.display__heading {
font-size: clamp(2.5rem, 6vw, 5rem);
}
clamp() for h1 through h3 and hero/display textclamp() -- a fixed rem value works finevw unit in the preferred value controls how aggressively the text scales2vw (gentle), 3vw (moderate), 5vw (aggressive)Provide multiple image resolutions so the browser picks the best one for the viewport and pixel density.
<img
src="image-800.jpg"
srcset="image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w"
sizes="(min-width: 1024px) 50vw,
(min-width: 768px) 75vw,
100vw"
alt="Descriptive alt text"
loading="lazy"
>
<picture> ElementUse <picture> for art direction -- serving different crops or images per viewport.
<picture>
<source
media="(min-width: 1024px)"
srcset="hero-desktop.jpg"
>
<source
media="(min-width: 768px)"
srcset="hero-tablet.jpg"
>
<img
src="hero-mobile.jpg"
alt="Hero image description"
loading="lazy"
>
</picture>
In WordPress templates, use the built-in function to output responsive images automatically.
<?php
$image_id = prefix_get_field('hero_image');
if ($image_id) :
// WordPress generates srcset automatically from registered image sizes
echo wp_get_attachment_image($image_id, 'large', false, array(
'class' => 'hero__image',
'loading' => 'lazy',
'sizes' => '(min-width: 1024px) 50vw, 100vw',
));
endif;
?>
If you have an image array (from ACF/SCF) instead of just the ID:
<?php
$image = prefix_get_field('hero_image');
if ($image) :
?>
<img
src="<?php echo esc_url($image['url']); ?>"
srcset="<?php echo esc_attr($image['sizes']['medium'] . ' 300w, ' . $image['sizes']['large'] . ' 1024w, ' . $image['url'] . ' ' . $image['width'] . 'w'); ?>"
sizes="(min-width: 1024px) 50vw, 100vw"
alt="<?php echo esc_attr($image['alt']); ?>"
width="<?php echo esc_attr($image['width']); ?>"
height="<?php echo esc_attr($image['height']); ?>"
loading="lazy"
>
<?php endif; ?>
Add loading="lazy" to all images below the fold. Do NOT add it to the hero/LCP image (which should be preloaded instead).
<!-- Hero image: NO lazy loading (it's the LCP element) -->
<img src="hero.jpg" alt="Hero" fetchpriority="high">
<!-- Below-the-fold images: lazy loaded -->
<img src="service.jpg" alt="Service" loading="lazy">
All interactive elements (links, buttons, form inputs) MUST have a minimum tap area of 44x44 pixels on touch devices.
.btn {
min-height: 44px;
min-width: 44px;
padding: var(--spacing-sm) var(--spacing-lg);
}
.nav__link {
display: inline-flex;
align-items: center;
min-height: 44px;
padding: var(--spacing-sm) var(--spacing-md);
}
.mobile-menu__link {
display: block;
padding: var(--spacing-md) var(--spacing-lg);
min-height: 44px;
}
input[type="text"],
input[type="email"],
input[type="tel"],
textarea,
select {
min-height: 44px;
padding: var(--spacing-sm) var(--spacing-md);
font-size: var(--font-size-base); /* Prevents zoom on iOS */
}
For small icon buttons (close, hamburger, social links), ensure the clickable area is at least 44px even if the visible icon is smaller.
.icon-button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
padding: var(--spacing-sm);
}
When building any section, you MUST define how it looks at each major breakpoint. No section should rely on desktop-only styles.
/* ============ Section: Values ============ */
/* Base: mobile */
.values {
padding: var(--spacing-2xl) 0;
}
.values__grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-lg);
}
.values__title {
font-size: clamp(1.5rem, 3vw, 2.5rem);
text-align: center;
margin-bottom: var(--spacing-xl);
}
/* Tablet (768px+) */
@media (min-width: 768px) {
.values__grid {
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-xl);
}
}
/* Desktop (1024px+) */
@media (min-width: 1024px) {
.values {
padding: var(--spacing-3xl) 0;
}
.values__grid {
grid-template-columns: repeat(3, 1fr);
}
}
The page MUST NOT scroll horizontally at any viewport width. This is tested starting at 320px minimum.
/* Prevent overflow from images */
img {
max-width: 100%;
height: auto;
}
/* Prevent overflow from fixed-width elements */
.container {
width: 100%;
overflow-x: hidden; /* Only as a last resort on the body/container */
}
/* Prevent overflow from long words/URLs */
.content {
overflow-wrap: break-word;
word-wrap: break-word;
}
/* Prevent overflow from pre/code blocks */
pre, code {
overflow-x: auto;
max-width: 100%;
}
/* Prevent overflow from tables */
.table-wrapper {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
Before finalizing, verify no horizontal scroll exists at these widths:
Respect the user's preference to reduce animations and motion.
/* Define animations normally */
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
}
/* Remove animations for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
This MUST be included in every stylesheet that uses animations or transitions.
Section vertical padding should scale with the viewport.
.section {
padding: var(--spacing-2xl) 0;
}
@media (min-width: 768px) {
.section {
padding: var(--spacing-3xl) 0;
}
}
@media (min-width: 1200px) {
.section {
padding: calc(var(--spacing-3xl) * 1.5) 0;
}
}
While clamp() handles most heading sizes, ensure consistent scaling across the page.
/* Mobile base sizes */
h1 { font-size: clamp(2rem, 5vw, 3.5rem); }
h2 { font-size: clamp(1.5rem, 3.5vw, 2.5rem); }
h3 { font-size: clamp(1.25rem, 2.5vw, 1.75rem); }
h4 { font-size: var(--font-size-lg); }
p {
font-size: var(--font-size-base);
line-height: var(--line-height-normal);
}
@media (min-width: 768px) {
p {
font-size: var(--font-size-md);
}
}
Footers typically use a multi-column grid on desktop and stack on mobile.
.footer__grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-xl);
}
@media (min-width: 768px) {
.footer__grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.footer__grid {
grid-template-columns: 2fr 1fr 1fr 1fr;
}
}
.footer__bottom {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
text-align: center;
padding-top: var(--spacing-xl);
border-top: 1px solid var(--color-border);
margin-top: var(--spacing-xl);
}
@media (min-width: 768px) {
.footer__bottom {
flex-direction: row;
justify-content: space-between;
text-align: left;
}
}
Before marking any page or section as complete, verify responsiveness at these viewport widths:
| Width | Device Class | Check |
|---|---|---|
| 375px | Mobile (iPhone SE) | Layout stacks, text readable, touch targets 44px+ |
| 576px | Large phone | Grid may shift to 2 columns |
| 768px | Tablet | 2-column layouts, larger padding |
| 1024px | Desktop | Full navigation visible, 3+ column grids |
| 1440px | Large desktop | Max container width respected, generous whitespace |
prefers-reduced-motion disables animationsmin-width media queries onlyclamp() used for headings and display textsrcset, sizes, and loading="lazy"wp_get_attachment_image() used in templatesprefers-reduced-motion media query included