Skip to main content

Overview

Ficha Dubai is built with a mobile-first responsive design strategy, ensuring optimal viewing and interaction across all device sizes from smartphones to large desktop displays.

Viewport Configuration

The application uses proper viewport meta tags for mobile optimization:
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
Code location: index.html:5
This meta tag ensures the layout scales correctly on mobile devices and prevents unwanted zooming.

Responsive Thumbnail System

The gallery dynamically adjusts the number of thumbnails displayed based on screen width:
const getThumbsPerPage = () => {
  return window.innerWidth < 768 ? 4 : 8;
};
Code location: app.js:31-33

Mobile (< 768px)

4 thumbnails per page

Desktop (≥ 768px)

8 thumbnails per page

Handling Window Resize

The application listens for window resize events and adjusts the gallery:
// Handle window resize
window.addEventListener("resize", () => {
  const newPerPage = getThumbsPerPage();
  if (newPerPage !== galleryThumbsPerPage) {
    galleryThumbsPerPage = newPerPage;
    galleryThumbPage = Math.floor(galleryCurrentIndex / galleryThumbsPerPage);
    renderThumbnails();
  }
});
Code location: app.js:380-387
The gallery automatically recalculates pagination when the viewport changes, ensuring a seamless experience when rotating devices or resizing windows.

Tailwind CSS Breakpoints

The project uses Tailwind CSS’s responsive utilities with these breakpoints:
BreakpointMin WidthPrefix
Mobile< 640px(default)
Small640pxsm:
Medium768pxmd:
Large1024pxlg:
Extra Large1280pxxl:
2X Large1536px2xl:

Responsive Grid Layouts

Main Content Grid

The page uses a responsive two-column layout:
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
  <!-- Left Column -->
  <div class="lg:col-span-8 space-y-8">
    <!-- Gallery, description, details -->
  </div>
  
  <!-- Right Column (Sidebar) -->
  <aside class="lg:col-span-4">
    <div class="sticky top-8 space-y-6">
      <!-- Contact card -->
    </div>
  </aside>
</div>
Code location: index.html:96-228 Layout behavior:
  • Mobile/Tablet (< 1024px): Single column, sidebar appears below content
  • Desktop (≥ 1024px): 8/4 column split with sticky sidebar
<div id="gallery-thumbnails" class="flex-1 grid grid-cols-4 md:grid-cols-8 gap-2"></div>
Code location: index.html:129 Grid columns:
  • Mobile: 4 columns
  • Desktop (md:): 8 columns

Details Grid

<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
  <!-- Description section -->
  <!-- Details section -->
</div>
Code location: index.html:140 Layout:
  • Mobile: Stacked vertically
  • Tablet/Desktop (md:): Two-column side-by-side

Responsive Typography

Typography scales with viewport size using Tailwind utilities:

Property Title

<h1 id="property-title" class="text-4xl md:text-5xl font-display font-extrabold text-white mb-4">
Code location: index.html:78
  • Mobile: text-4xl (2.25rem / 36px)
  • Desktop: text-5xl (3rem / 48px)

Price Display

<p id="property-price" class="text-3xl font-display font-bold">--</p>
Code location: index.html:87 Consistent size across all devices for prominence

Responsive Components

Header Layout

<div class="flex flex-col md:flex-row justify-between items-start gap-6">
  <div>
    <!-- Title and badges -->
  </div>
  <div class="bg-white/10 backdrop-blur-lg border border-white/20 p-6 rounded-2xl text-white min-w-[240px]">
    <!-- Price card -->
  </div>
</div>
Code location: index.html:75-90 Behavior:
  • Mobile: Vertical stack
  • Desktop: Horizontal flex with space-between
<button id="lightbox-prev" class="absolute left-4 top-1/2 -translate-y-1/2 p-3 md:p-4 rounded-full bg-white/10 hover:bg-white/20 text-white transition-colors z-10">
  <span class="material-icons-outlined text-2xl md:text-3xl">chevron_left</span>
</button>
Code location: index.html:248-250 Sizing:
  • Mobile: p-3, text-2xl icons
  • Desktop: p-4, text-3xl icons
<div class="relative max-w-[90vw] max-h-[70vh] md:max-h-[75vh] flex items-center justify-center">
  <img id="lightbox-image" class="max-w-full max-h-[65vh] md:max-h-[70vh] object-contain rounded-lg shadow-2xl" src="" alt=""/>
</div>
Code location: index.html:254-256 Max heights:
  • Mobile: 65vh/70vh container
  • Desktop: 70vh/75vh container
thumb.className = `lightbox-thumb w-12 h-12 md:w-14 md:h-14 rounded-lg overflow-hidden cursor-pointer transition-all flex-shrink-0 ${isActive ? "ring-2 ring-white" : "opacity-50 hover:opacity-80"}`;
Code location: app.js:118 Thumbnail size:
  • Mobile: 48×48px (w-12 h-12)
  • Desktop: 56×56px (w-14 h-14)

Container Constraints

The main content container limits maximum width:
<main class="max-w-7xl mx-auto px-6 lg:px-12 -mt-20 pb-20 relative z-20">
Code location: index.html:95 Horizontal padding:
  • Mobile/Tablet: px-6 (1.5rem)
  • Desktop: px-12 (3rem)
Max width: 7xl = 80rem (1280px)

Responsive Images

<div class="relative aspect-[16/9] w-full rounded-xl overflow-hidden mb-4 group">
  <img id="gallery-main-image" alt="Imagen principal" class="w-full h-full object-cover" src=""/>
Code location: index.html:101-102 Aspect ratio: Fixed 16:9 ratio maintains consistent gallery height Object fit: object-cover ensures images fill the container without distortion

Thumbnail Images

thumb.className = `thumbnail-item aspect-square rounded-md overflow-hidden bg-slate-100 dark:bg-slate-700 cursor-pointer transition ${isActive ? "ring-2 ring-primary opacity-100" : "opacity-80 hover:opacity-100"}`;
Code location: app.js:300 Aspect ratio: Square (1:1) for uniform thumbnail grid

Responsive Spacing

The application uses consistent spacing scales:
<div class="space-y-8"><!-- 2rem gap between sections --></div>
<div class="gap-8"><!-- 2rem gap in grids --></div>
<div class="space-y-6"><!-- 1.5rem gap for tighter grouping --></div>

Mobile-First CSS

Custom styles in styles.css follow mobile-first principles:
.container {
  width: min(1200px, 92vw);
  margin: 0 auto;
}

@media (max-width: 900px) {
  .gallery-section {
    grid-template-columns: 1fr;
  }

  .price-card {
    width: 100%;
  }
}
Code location: styles.css:27-329
Base styles apply to all devices, with media queries adding complexity for larger screens.

Touch Optimization

Interactive elements use appropriate sizing for touch targets:
<button id="thumb-prev" class="flex-shrink-0 p-2 rounded-full bg-slate-100 dark:bg-slate-700 hover:bg-slate-200 dark:hover:bg-slate-600 text-slate-600 dark:text-slate-300 transition-colors disabled:opacity-30 disabled:cursor-not-allowed">
  <span class="material-icons-outlined text-xl">chevron_left</span>
</button>
Code location: index.html:126-128 Touch target: Icon + padding creates minimum 44×44px touch area (accessibility guideline)

Performance Considerations

The map iframe uses loading="lazy" to defer loading until needed:
iframe.loading = "lazy";
Code location: app.js:558
JavaScript loads with defer attribute for non-blocking page rendering:
<script src="app.js" defer></script>
Code location: index.html:277
All images use object-cover or object-contain for efficient rendering without layout shifts.

Responsive Design Patterns

1

Mobile First

Base styles target smallest screens, progressively enhanced for larger viewports
2

Fluid Typography

Text scales smoothly with viewport using Tailwind’s responsive classes
3

Flexible Grids

CSS Grid adapts from single-column to multi-column layouts
4

Adaptive Images

Images maintain aspect ratios and optimize for available space
5

Touch-Friendly

Interactive elements sized appropriately for finger taps

Testing Breakpoints

Test the application at these key widths:
Device TypeWidthKey Changes
Mobile375px4 thumbnails, single column layout
Mobile Large414pxSame as mobile
Tablet768px8 thumbnails, larger icons
Desktop1024pxTwo-column layout with sticky sidebar
Large Desktop1280pxMaximum content width reached

Build docs developers (and LLMs) love