Home >Web Front-end >CSS Tutorial >A Top Navigation Menu for a Klondike Solitaire Games, That Changes Aspect on Mobile Devices
I'm working on a klondike solitaire game and I created a menu that is displayed on the top of the page. On laptops and computers I want to look like regular menus, considering many players are used to such menus, but on mobile devices, I wanted the menu items to be easy to click.
<div class="menu-bar" id="menuBar"></div>
Here is the css style for the regular menu:
body { padding: 0; margin: 0; } /* Basic menu styling for desktop */ .menu-bar { display: flex; background-color: #333; padding: 10px; justify-content: flex-start; /* Align menu items to the left */ font-family: Arial, Helvetica, sans-serif } .menu-item { color: white; padding: 10px; cursor: pointer; position: relative; text-align: center; flex: 0; display: flex; /* Align icon and text on the same line */ align-items: center; justify-content: center; white-space: nowrap; } .menu-item { text-align: left; } .menu-item i { font-size: 1.5rem; margin-right: 8px; /* Space between icon and text */ } .menu-item .shortcut, .submenu-item .shortcut { color: #999; } .menu-item .shortcut { display: none; /* too ugly on main items */ } .submenu { display: none; position: absolute; background-color: #444; top: 40px; left: 0; width: 150px; } .submenu-item { padding: 10px; color: white; } .submenu-item:hover { background-color: #666; } .menu-item.active .submenu { display: block; }
To make the menu act differently on mobile devices we are going to use media queries:
/* Mobile styles */ @media (max-width: 768px) { .menu-bar { flex-direction: column; position: relative; display: grid; /* Grid layout for mobile */ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); /* Evenly divide menu items into columns */ gap: 10px; } .menu-item { padding: 15px 5px; display: block; /* Stack icon and text vertically on mobile */ white-space: normal; } .menu-item { text-align: center; } .menu-item i { font-size: 2rem; /* Larger icon for mobile */ margin-right: 0; /* Remove margin on mobile */ display: block; /* Icon on a separate line */ text-align: center; } .menu-item .shortcut { display: none; /* Hide shortcuts on mobile */ } .submenu { position: static; display: none; width: 100%; background-color: #333; top: 0; left: 0; z-index: 10; } .menu-item.active .submenu { display: block; } .menu-bar.active .menu-item { display: none; } .menu-bar.active .menu-item.active { display: block; } .submenu .close-btn { color: white; padding: 10px; cursor: pointer; text-align: center; background-color: #444; } .submenu .close-btn:hover { background-color: #666; } }
and finally the javascript:
const menuData = [ { icon: "fa-solid fa-gamepad", // Icon for "New Game..." icon_text: "?", // Emoji for game controller name: "New Game...", shortcut: "", submenu: { items: [ { name: "Restart", icon: "fa-solid fa-undo-alt", // Icon for "Restart" icon_text: "?", // Emoji for restart shortcut: "Ctrl+N" }, { name: "Start New", icon: "fa-solid fa-play-circle", // Icon for "Start New" icon_text: "▶️", // Emoji for start/play shortcut: "" } ] } }, { icon: "fa-solid fa-cog", // Icon for "Settings..." name: "Settings...", icon_text: "⚙️", // Emoji for settings shortcut: "Ctrl+S", submenu: null }, { icon: "fa-solid fa-th-large", // Icon for "More Solitaire..." icon_text: "?", // Emoji for cards/games name: "More Solitaire...", shortcut: "Ctrl+P", submenu: null } ]; function createMenu(menuData) { const mode = "emoji"; const menuBar = document.getElementById('menuBar'); menuData.forEach(item => { const menuItem = document.createElement('div'); menuItem.classList.add('menu-item'); // Add icon const icon = document.createElement('i'); (mode === "emoji") ? (icon.innerText = item.icon_text, icon.style["font-style"] = "normal") : icon.className = item.icon; menuItem.appendChild(icon); // Add name const name = document.createElement('div'); name.textContent = item.name; menuItem.appendChild(name); // Add shortcut if available if (item.shortcut) { const shortcut = document.createElement('span'); shortcut.classList.add('shortcut'); shortcut.textContent = ` (${item.shortcut})`; menuItem.appendChild(shortcut); } // Check for submenu if (item.submenu) { const submenu = document.createElement('div'); submenu.classList.add('submenu'); item.submenu.items.forEach(subItem => { const submenuItem = document.createElement('div'); submenuItem.classList.add('submenu-item'); // Submenu item icon const subIcon = document.createElement('i'); (mode === "emoji") ? (subIcon.innerText = subItem.icon_text, subIcon.style["font-style"] = "normal") : subIcon.className = subItem.icon; submenuItem.appendChild(subIcon); // Submenu item name const subName = document.createTextNode(` ${subItem.name}`); submenuItem.appendChild(subName); // Submenu item shortcut if (subItem.shortcut) { const subShortcut = document.createElement('span'); subShortcut.classList.add('shortcut'); subShortcut.textContent = ` (${subItem.shortcut})`; submenuItem.appendChild(subShortcut); } submenu.appendChild(submenuItem); }); // Add a close button at the end of the submenu for mobile const closeButton = document.createElement('div'); closeButton.classList.add('submenu-item'); // Make it look like other submenu items // Add the chevron icon const closeIcon = document.createElement('i'); (mode === "emoji") ? (closeIcon.innerText = '⬆️', closeIcon.style["font-style"] = "normal") : closeIcon.className = 'fa-solid fa-chevron-up'; closeButton.appendChild(closeIcon); // Add the "Close" text const closeText = document.createTextNode(' Close'); closeButton.appendChild(closeText); closeButton.addEventListener('click', function (event) { event.stopPropagation(); // Prevent the click from propagating to the parent .menu-item menuItem.classList.remove('active'); // Close the submenu }); submenu.appendChild(closeButton); menuItem.appendChild(submenu); // Add event listener for clicking to show/hide submenu menuItem.addEventListener('click', function (event) { event.stopPropagation(); // Prevent closing when clicking inside the menu const allMenuItems = document.querySelectorAll('.menu-item'); if (window.innerWidth <= 768) { allMenuItems.forEach(item => item.classList.remove('active')); // Close all menuItem.classList.add('active'); // Open clicked one } else { menuItem.classList.toggle('active'); // Toggle submenu on desktop } }); // Close the submenu when clicking outside of the menu document.addEventListener('click', function (event) { const allMenuItems = document.querySelectorAll('.menu-item'); allMenuItems.forEach(menuItem => { if (!menuItem.contains(event.target)) { menuItem.classList.remove('active'); // Close the submenu if clicked outside } }); }); } menuBar.appendChild(menuItem); }); } // Initialize the menu createMenu(menuData); // Add resize event listener to handle dynamic resizing window.addEventListener('resize', function () { const menuBar = document.getElementById('menuBar'); if (window.innerWidth > 768) { // On desktop, ensure that all submenus are collapsed by default const allMenuItems = document.querySelectorAll('.menu-item'); allMenuItems.forEach(item => item.classList.remove('active')); } });
You can play with the code here:
https://codepen.io/quantotius/pen/KKOWjyd
The above is the detailed content of A Top Navigation Menu for a Klondike Solitaire Games, That Changes Aspect on Mobile Devices. For more information, please follow other related articles on the PHP Chinese website!