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:
- Domain Bar (Optional)
- Fixed position at the very top
- Can be hidden via
$hide_domain_barparameter - Contains domain-related information
- 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
- Navigation Bar (
#skysnag-header)
- Sticky positioned below the top bar
- Contains main navigation menu and logo
- On mobile/tablet: Hidden (
lg:hiddenon 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:hiddenclass (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: 640pxmd: 768pxlg: 1024pxxl: 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:hiddenclass in top bar) - Navigation Bar: Hidden (logo and menu not visible)
- Desktop announcement: Hidden (
max-lg:hiddenclass) - Mobile announcement: Visible (
lg:hiddenclass)
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:hiddenremoved) - Mobile announcement: Hidden (
lg:hiddenapplied)
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?
- Performance: No JavaScript execution needed, faster page load
- Reliability: No dependency on JavaScript being enabled
- Simplicity: Easier to maintain and debug
- SEO: Content is immediately available in the HTML
Evolution of Approach:
- Initial: JavaScript dynamically created mobile announcement
- 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
skysnag_is_top_bar_announcement_enabled()
- Checks if announcement feature is enabled
skysnag_get_top_bar_option($key, $default, $lang)
- Retrieves language-specific option values
- Returns empty string if language-specific value doesn’t exist
skysnag_should_top_bar_open_new_tab()
- Checks admin setting for link behavior
Data Flow
- Admin saves settings → Stored in WordPress options table
- Template loads → Helper functions retrieve values
- Language detection → Current language determines which values to use
- Conditional rendering → Only displays if enabled and text exists
- 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:
- Dismissible Announcements: Allow users to dismiss announcements with localStorage
- Scheduled Announcements: Add date/time scheduling for announcements
- A/B Testing: Support multiple announcement variants
- Analytics Integration: Track click-through rates
- 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.