Building a Responsive Top Bar Announcement: Challenges and Solutions

Overview

This document outlines the development process of a responsive top bar announcement feature for a WordPress website. The feature needed to display announcement messages across different device sizes while maintaining a clean, uncluttered header design.

The Three-Bar Header Structure

Before diving into the challenges, it’s important to understand the header architecture. The website uses a three-bar system at the top of the page:

  1. Domain Bar (Optional)
  • Fixed position at the very top
  • Can be hidden via $hide_domain_bar parameter
  • Contains domain-related information
  1. Top Bar (Announcement Bar)
  • Positioned below the domain bar
  • Contains the announcement message
  • Fixed height of 40px (h-10)
  • On mobile/tablet: Includes the logo (since navigation bar is hidden)
  • On desktop: Logo is hidden, announcement text is displayed
  1. Navigation Bar (#skysnag-header)
  • Sticky positioned below the top bar
  • Contains main navigation menu and logo
  • On mobile/tablet: Hidden (lg:hidden on logo, burger menu shown)
  • On desktop: Visible with full navigation

This three-bar structure created unique challenges, particularly around logo visibility and space management on different screen sizes.

The Challenge

The initial requirement was straightforward: display an announcement message in the top bar of the website. However, several challenges emerged during implementation:

Challenge 1: Mobile and Tablet Visibility

Problem: The announcement was initially hidden on mobile and tablet devices using max-md:hidden (hidden below 768px). This meant users on smaller screens couldn’t see important announcements.

Why it mattered: Mobile users represent a significant portion of web traffic, and missing announcements could impact user engagement and conversion rates.

Initial Approach: We attempted to show the announcement on mobile by removing the max-md:hidden class, but this created a new problem—the announcement competed for space with the logo and menu icons, making the header cluttered and difficult to use.

Challenge 2: Logo Visibility on Mobile Devices

Problem: The navigation bar (which contains the main logo) is hidden on mobile and tablet devices. This meant users on smaller screens had no way to see the site logo, which is crucial for brand recognition and navigation back to the homepage.

Why it mattered:

  • Brand identity requires logo visibility across all devices
  • Users expect to find logos in headers for navigation
  • Missing logo creates confusion and reduces trust

Initial Discovery: When we examined the header structure, we found that:

  • The navigation bar logo uses lg:hidden class (hidden below 1024px)
  • Mobile users only see a burger menu icon
  • The top bar was the only visible header element on mobile

Solution Strategy: We added the logo to the top bar on mobile devices using lg:hidden class, ensuring it’s visible when the navigation bar is hidden. This maintains brand presence while keeping the header functional.

Code Implementation:

<!-- Logo in top bar (visible on mobile/tablet, hidden on desktop) -->
<a href="<?= get_language_specific_url('home') ?>" 
   class="lg:hidden h-full w-auto items-center p-0 pr-4 flex">
  <img src="<?php echo get_theme_file_uri('/assets/img/skysnag-wordmark.svg') ?>" 
       alt="skysnag logo" class="logo h-4" />
</a>

Challenge 3: Maintaining Header Clarity

Problem: With the logo now in the top bar on mobile devices, adding the announcement to the same bar would create a cluttered interface competing for limited space with the logo and menu icons.

User Experience Impact: A cluttered header reduces usability and can frustrate users trying to navigate the site.

Solution Strategy: Instead of showing the announcement in the top bar on mobile, we decided to display it below the top bar, preserving the header’s clean design while ensuring the announcement remains visible.

Challenge 4: Responsive Breakpoint Alignment

Problem: The logo visibility was controlled by lg:hidden (visible below 1024px), but the announcement was using max-md:hidden (hidden below 768px). This created a mismatch where tablets (768px – 1023px) would show the logo but not the announcement.

Technical Details:

  • Tailwind CSS breakpoints:
  • sm: 640px
  • md: 768px
  • lg: 1024px
  • xl: 1280px

Impact: Users in the tablet range (768px – 1023px) would see the logo but miss the announcement, creating an inconsistent experience.

Challenge 5: Language-Specific Content Without Fallbacks

Problem: The announcement needed to support multiple languages (English, Spanish, German, French, Portuguese-BR, Japanese), but we didn’t want to fall back to English when a language-specific version wasn’t available.

Why no fallback? The client wanted complete control over which languages display announcements. For example, if they only configured German announcements, they didn’t want English users to see a default message.

Implementation Requirement: The announcement should only display if a translation exists for the current language, otherwise it should remain hidden entirely.

Challenge 6: Dynamic Link Behavior

Problem: The announcement link needed to support both same-page navigation and opening in a new tab, controlled by an admin setting.

User Need: Content managers wanted flexibility to control whether announcement links open in the same tab or a new tab, depending on the destination and user experience goals.

Solutions Implemented

Solution 1: Logo Integration in Top Bar

To address the missing logo on mobile devices, we integrated the logo directly into the top bar. The logo appears only when the navigation bar is hidden (below 1024px), ensuring brand visibility across all device sizes.

Implementation Logic:

<!-- Logo appears in top bar on mobile/tablet -->
<a href="<?= get_language_specific_url('home') ?>" 
   class="lg:hidden h-full w-auto items-center p-0 pr-4 flex">
  <img src="<?php echo get_theme_file_uri('/assets/img/skysnag-wordmark.svg') ?>" 
       alt="skysnag logo" class="logo h-4" />
</a>

<!-- Desktop announcement (logo is in navigation bar, not here) -->
<a class="max-lg:hidden ...">Desktop Announcement</a>

Breakpoint Behavior:

  • Below 1024px: Logo visible in top bar, navigation bar hidden
  • 1024px and above: Logo in navigation bar, top bar shows announcement only

Solution 2: Separate Mobile Announcement Section

Instead of trying to fit the announcement into the top bar on mobile devices, we created a dedicated section below the top bar that appears only on mobile and tablet devices.

Implementation:

<!-- Desktop announcement (hidden on mobile/tablet) -->
<a class="max-lg:hidden flex flex-wrap items-center gap-1.5 ..."
   href="<?php echo esc_url($announcement_url); ?>">
  <!-- Announcement content -->
</a>

<!-- Mobile/Tablet announcement (shown on mobile/tablet, hidden on desktop) -->
<section id="skysnag-mobile-announcement" class="lg:hidden w-full bg-white border-b border-gray-100">
  <div class="<?php echo $width_style; ?> w-full relative mx-auto px-4 py-2">
    <a class="flex flex-wrap items-center gap-1.5 ..."
       href="<?php echo esc_url($announcement_url); ?>">
      <!-- Same announcement content -->
    </a>
  </div>
</section>

Benefits:

  • Preserves header clarity on mobile devices
  • Ensures announcement visibility across all device sizes
  • Maintains consistent styling between desktop and mobile versions

Solution 3: Unified Breakpoint Strategy

We aligned all responsive breakpoints to use the lg breakpoint (1024px) to ensure consistent behavior across components.

Breakpoint Logic:

Below 1024px (mobile + tablets):

  • Domain Bar: Visible (if enabled)
  • Top Bar Logo: Visible (lg:hidden class in top bar)
  • Navigation Bar: Hidden (logo and menu not visible)
  • Desktop announcement: Hidden (max-lg:hidden class)
  • Mobile announcement: Visible (lg:hidden class)

1024px and above (desktop):

  • Domain Bar: Visible (if enabled)
  • Top Bar Logo: Hidden (logo moves to navigation bar)
  • Navigation Bar: Visible (contains logo and full menu)
  • Desktop announcement: Visible (max-lg:hidden removed)
  • Mobile announcement: Hidden (lg:hidden applied)

Code Example:

// Logo visibility
<a href="..." class="lg:hidden ...">Logo</a>

// Desktop announcement
<a class="max-lg:hidden ...">Desktop Announcement</a>

// Mobile announcement
<section class="lg:hidden ...">Mobile Announcement</section>

Solution 4: Language-Specific Content Retrieval

We implemented a helper function that returns an empty string when a language-specific value doesn’t exist, rather than falling back to a default.

Helper Function:

function skysnag_get_top_bar_option($key, $default = '', $lang = null)
{
  if ($lang === null) {
    $lang = get_language_shortcode();
  }

  $language_fields = array('announcement_text', 'announcement_link_slug', 'announcement_link_text');

  if (in_array($key, $language_fields)) {
    $lang_key = $key . '_' . $lang;
    // Return empty string if language-specific value doesn't exist
    return skysnag_get_website_data('skysnag_top_bar_data', $lang_key, '');
  }

  return skysnag_get_website_data('skysnag_top_bar_data', $key, $default);
}

Display Logic:

if ($announcement_enabled && !empty($announcement_text)) :
  // Only display if text exists for current language
endif;

Result: If a German announcement is configured but no English version exists, English users won’t see any announcement, giving content managers complete control.

Solution 5: Admin-Controlled Link Behavior

We added an admin setting that allows content managers to control whether announcement links open in a new tab.

Admin Interface:

<div class="skysnag-enable-toggle">
  <label>
    <input type="checkbox" name="announcement_open_new_tab" value="1" />
    <span>Open Link in New Tab</span>
  </label>
</div>

Frontend Implementation:

$open_new_tab = skysnag_should_top_bar_open_new_tab();
$target_attr = $open_new_tab ? 'target="_blank"' : '';

<a href="<?php echo esc_url($announcement_url); ?>" <?php echo $target_attr; ?>>

Solution 6: CSS-Only Approach (Final Implementation)

After initially implementing a JavaScript-based solution, we simplified to a pure CSS approach using Tailwind’s responsive utilities.

Why CSS over JavaScript?

  1. Performance: No JavaScript execution needed, faster page load
  2. Reliability: No dependency on JavaScript being enabled
  3. Simplicity: Easier to maintain and debug
  4. SEO: Content is immediately available in the HTML

Evolution of Approach:

  1. Initial: JavaScript dynamically created mobile announcement
  2. Final: Static PHP section with CSS classes for show/hide

Final Code Structure:

<?php
// Get announcement data
$announcement_enabled = skysnag_is_top_bar_announcement_enabled();
$announcement_text = skysnag_get_top_bar_option('announcement_text', '');
// ... other variables

if ($announcement_enabled && !empty($announcement_text)) :
?>
  <!-- Desktop version -->
  <a class="max-lg:hidden ...">...</a>

  <!-- Mobile version -->
  <section class="lg:hidden ...">...</section>
<?php endif; ?>

Technical Architecture

File Structure

partials/header/top-bar.php          # Main template file
includes/options-helpers.php         # Helper functions
includes/admin/options/data/top-bar.php  # Admin settings

Key Functions

  1. skysnag_is_top_bar_announcement_enabled()
  • Checks if announcement feature is enabled
  1. skysnag_get_top_bar_option($key, $default, $lang)
  • Retrieves language-specific option values
  • Returns empty string if language-specific value doesn’t exist
  1. skysnag_should_top_bar_open_new_tab()
  • Checks admin setting for link behavior

Data Flow

  1. Admin saves settings → Stored in WordPress options table
  2. Template loads → Helper functions retrieve values
  3. Language detection → Current language determines which values to use
  4. Conditional rendering → Only displays if enabled and text exists
  5. CSS classes → Control visibility based on screen size

Best Practices Applied

1. Progressive Enhancement

  • Content is available in HTML regardless of JavaScript
  • CSS handles responsive behavior

2. Separation of Concerns

  • PHP handles data retrieval and logic
  • CSS handles presentation and responsive behavior
  • Admin interface handles configuration

3. Accessibility

  • Semantic HTML structure
  • Proper link attributes
  • Screen reader friendly

4. Performance

  • No JavaScript overhead
  • CSS-only responsive behavior
  • Efficient database queries

5. Maintainability

  • Clear function names
  • Consistent code structure
  • Well-documented logic

Lessons Learned

1. Start Simple, Then Optimize

We initially implemented a JavaScript solution, but discovered that CSS alone could handle the responsive behavior more efficiently. This taught us to always consider the simplest solution first.

2. Understanding the Full Header Structure

The three-bar header system required careful consideration of each bar’s visibility and purpose. The logo’s placement needed to adapt based on which bars were visible, leading to the mobile logo in the top bar solution.

3. Breakpoint Consistency Matters

Mismatched breakpoints created user experience issues. Aligning all components to use the same breakpoint (lg: 1024px) ensured consistent behavior across devices. This was especially important given the three-bar structure where each bar’s visibility affects the others.

4. Content Control is Important

Giving content managers granular control over language-specific content prevents unintended message displays and maintains brand consistency.

5. CSS Over JavaScript When Possible

For simple show/hide behavior, CSS classes are more performant and reliable than JavaScript. Reserve JavaScript for interactive features that truly require it.

6. User Experience First

Preserving header clarity on mobile devices was more important than showing the announcement in the same location. Sometimes the best solution requires rethinking the layout.

Future Enhancements

Potential improvements for future iterations:

  1. Dismissible Announcements: Allow users to dismiss announcements with localStorage
  2. Scheduled Announcements: Add date/time scheduling for announcements
  3. A/B Testing: Support multiple announcement variants
  4. Analytics Integration: Track click-through rates
  5. Rich Content: Support for HTML content and images

Conclusion

Building a responsive top bar announcement feature required balancing multiple concerns: visibility, usability, performance, and maintainability. By using a CSS-first approach, maintaining consistent breakpoints, and providing granular content control, we created a solution that works seamlessly across all device sizes while remaining easy to maintain and extend.

The key takeaway: sometimes the simplest solution (CSS classes) is the best solution, and user experience should always guide technical decisions.