PluginBench
Skill
Review
Audit score 70

mobile-responsiveness

hoodini/ai-agents-skills

Build responsive, mobile-first web applications with breakpoints, touch interactions, and adaptive layouts.

What is mobile-responsiveness?

This skill provides patterns for creating web applications that work seamlessly across mobile, tablet, and desktop devices. Use it when implementing responsive layouts, touch interactions, mobile navigation, or optimizing for various screen sizes.

  • Define mobile-first CSS breakpoints for tablet (768px), desktop (1024px), and large screens (1280px+)
  • Implement fluid typography using CSS clamp() for scalable text across viewport sizes
  • Handle touch interactions including swipe detection with configurable distance thresholds
  • Build collapsible mobile navigation with hamburger menus and backdrop overlays
  • Account for device safe areas (notches, home indicators) using CSS env() variables
  • Detect responsive breakpoints at runtime with useMediaQuery React hook

How to install mobile-responsiveness

npx skills add https://github.com/hoodini/ai-agents-skills --skill mobile-responsiveness
Claude Code
Cursor
Windsurf
Cline

How to use mobile-responsiveness

  1. 1.Set the viewport meta tag in your HTML head with width=device-width and viewport-fit=cover
  2. 2.Choose a breakpoint strategy: use mobile-first CSS media queries (768px, 1024px, 1280px) or Tailwind utility classes (md:, lg:, xl:)
  3. 3.For typography, define fluid font sizes using CSS clamp() or Tailwind's responsive text utilities
  4. 4.Implement touch interactions by tracking touchStart and touchEnd positions, calculating swipe distance, and triggering callbacks
  5. 5.Create mobile navigation with hidden hamburger button (md:hidden) and fixed overlay menu that transitions based on state
  6. 6.Test across actual devices or browser DevTools device emulation to verify breakpoints and touch interactions

Use cases

Good for
  • Creating a product listing page that displays as a single column on mobile, two columns on tablet, and three columns on desktop
  • Building a mobile app with swipe-to-dismiss card interactions and touch-friendly navigation
  • Implementing a header that collapses to a hamburger menu on screens under 768px width
  • Designing fluid typography that scales smoothly from 16px on small phones to 20px on large desktops
  • Adapting a bottom navigation bar to avoid overlap with iPhone home indicator using safe-area-inset-bottom
Who it's for
  • Frontend developers building cross-device web applications
  • React developers implementing responsive component libraries
  • Mobile-first web designers translating designs to code
  • Teams building progressive web apps (PWAs) for mobile and desktop

mobile-responsiveness FAQ

What's the difference between mobile-first and desktop-first responsive design?

Mobile-first applies base styles for mobile, then uses min-width media queries to add complexity for larger screens. Desktop-first does the opposite with max-width queries. Mobile-first is recommended because it's simpler and encourages performance optimization.

How do I handle the iPhone notch and home indicator?

Use CSS env(safe-area-inset-*) variables for padding and the viewport-fit=cover meta tag. For fixed bottom navigation, use padding-bottom: max(1rem, env(safe-area-inset-bottom)) to respect the home indicator.

Should I use CSS media queries or Tailwind breakpoints?

Both work; Tailwind is faster for rapid development with utility classes (md:p-8, lg:text-4xl), while custom CSS media queries offer more control. Choose based on your project setup and team preference.

How do I detect the current breakpoint in JavaScript?

Use the useMediaQuery hook with window.matchMedia() to detect breakpoints at runtime. For example, useMediaQuery('(max-width: 767px)') returns true on mobile devices.

What's the minimum swipe distance to avoid accidental triggers?

50 pixels is a common threshold that balances responsiveness with avoiding unintended swipes. Adjust based on your use case and user testing.

Full instructions (SKILL.md)

Source of truth, from hoodini/ai-agents-skills.


name: mobile-responsiveness description: Build responsive, mobile-first web applications. Use when implementing responsive layouts, touch interactions, mobile navigation, or optimizing for various screen sizes. Triggers on responsive design, mobile-first, breakpoints, touch events, viewport.

Mobile Responsiveness

Build responsive, mobile-first web applications.

Mobile-First Breakpoints

/* Mobile first - no media query needed for mobile base */
.container {
  padding: 1rem;
}

/* Tablet */
@media (min-width: 768px) {
  .container {
    padding: 2rem;
  }
}

/* Desktop */
@media (min-width: 1024px) {
  .container {
    padding: 3rem;
    max-width: 1200px;
    margin: 0 auto;
  }
}

/* Large desktop */
@media (min-width: 1280px) {
  .container {
    max-width: 1400px;
  }
}

Tailwind Breakpoints

<div className="
  p-4          /* Mobile: padding 1rem */
  md:p-8       /* Tablet 768px+: padding 2rem */
  lg:p-12      /* Desktop 1024px+: padding 3rem */
  xl:max-w-6xl /* Large 1280px+: max-width */
">
  <h1 className="
    text-2xl     /* Mobile */
    md:text-3xl  /* Tablet */
    lg:text-4xl  /* Desktop */
  ">
    Responsive Heading
  </h1>
</div>

Fluid Typography

:root {
  /* Fluid font size: 16px at 320px viewport, 20px at 1200px viewport */
  --font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
  
  /* Fluid heading */
  --font-size-h1: clamp(2rem, 1.5rem + 2.5vw, 4rem);
}

body {
  font-size: var(--font-size-base);
}

h1 {
  font-size: var(--font-size-h1);
}

Touch Interactions

import { useState } from 'react';

function SwipeableCard({ onSwipeLeft, onSwipeRight, children }) {
  const [touchStart, setTouchStart] = useState<number | null>(null);
  const [touchEnd, setTouchEnd] = useState<number | null>(null);

  const minSwipeDistance = 50;

  const onTouchStart = (e: React.TouchEvent) => {
    setTouchEnd(null);
    setTouchStart(e.targetTouches[0].clientX);
  };

  const onTouchMove = (e: React.TouchEvent) => {
    setTouchEnd(e.targetTouches[0].clientX);
  };

  const onTouchEnd = () => {
    if (!touchStart || !touchEnd) return;
    
    const distance = touchStart - touchEnd;
    const isLeftSwipe = distance > minSwipeDistance;
    const isRightSwipe = distance < -minSwipeDistance;
    
    if (isLeftSwipe) onSwipeLeft?.();
    if (isRightSwipe) onSwipeRight?.();
  };

  return (
    <div
      onTouchStart={onTouchStart}
      onTouchMove={onTouchMove}
      onTouchEnd={onTouchEnd}
    >
      {children}
    </div>
  );
}

Mobile Navigation

import { useState } from 'react';

function MobileNav() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      {/* Hamburger button - visible on mobile */}
      <button
        className="md:hidden p-2"
        onClick={() => setIsOpen(!isOpen)}
        aria-expanded={isOpen}
        aria-label="Toggle menu"
      >
        <span className={`hamburger ${isOpen ? 'open' : ''}`} />
      </button>

      {/* Mobile menu */}
      <nav
        className={`
          fixed inset-0 bg-white z-50 transform transition-transform
          ${isOpen ? 'translate-x-0' : '-translate-x-full'}
          md:static md:translate-x-0 md:bg-transparent
        `}
      >
        <ul className="flex flex-col md:flex-row gap-4 p-4 md:p-0">
          <li><a href="/">Home</a></li>
          <li><a href="/about">About</a></li>
          <li><a href="/contact">Contact</a></li>
        </ul>
      </nav>

      {/* Backdrop */}
      {isOpen && (
        <div
          className="fixed inset-0 bg-black/50 z-40 md:hidden"
          onClick={() => setIsOpen(false)}
        />
      )}
    </>
  );
}

Safe Areas (Notch/Home Indicator)

/* Account for iPhone notch and home indicator */
.container {
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
}

/* Fixed bottom navigation */
.bottom-nav {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  padding-bottom: max(1rem, env(safe-area-inset-bottom));
}

Viewport Meta Tag

<meta 
  name="viewport" 
  content="width=device-width, initial-scale=1, viewport-fit=cover"
/>

useMediaQuery Hook

import { useState, useEffect } from 'react';

function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);
    setMatches(media.matches);

    const listener = (e: MediaQueryListEvent) => setMatches(e.matches);
    media.addEventListener('change', listener);
    
    return () => media.removeEventListener('change', listener);
  }, [query]);

  return matches;
}

// Usage
function Component() {
  const isMobile = useMediaQuery('(max-width: 767px)');
  const isTablet = useMediaQuery('(min-width: 768px) and (max-width: 1023px)');
  const isDesktop = useMediaQuery('(min-width: 1024px)');

  return isMobile ? <MobileView /> : <DesktopView />;
}

Resources