Accessibility of responsive menu - css

I want to deepen my knowledge about accessibility. So I appreciate any feedback. Please check this code whether it fulfills (hopefully high) standards of accessibility for a responsive menu. I think that there may be some issues with keyboard navigation – but I don’t know.
First the HTML. Pls. notice the comments inside the HTML:
For convenience I list them here too:
Wrap navigation in nav tag. Don't use <div class="navigation">
Give navigation a role="navigation"
Don't wrap button in a tag or div. Instead use button
Give screenreader a hint, whether menu is expanded or hidden with area-expanded="Boolean". Add hint dynamically with JS.
So the complete HTML is:
<header class="header">
<!-- role=navigation to ensure better support, since not all browsers/screen readers will recognize the <nav> element. -->
<nav role="navigation" class="navbar">
companyLogo
<ul class="nav-menu">
<li class="nav-item"><a class="nav-link" href="#">Services</a></li>
<li class="nav-item"><a class="nav-link" href="#">About</a></li>
<li class="nav-item"><a class="nav-link" href="#">nav</a></li>
</ul>
<!-- By using aria-expanded attribute, the user will be able to know that the button content is expanded or collapsed. At first, we will add the attribute by default and then JavaScript will help changing the value.
https://www.a11ymatters.com/pattern/mobile-nav/ -->
<button class="hamburger" aria-expanded="false">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</button>
</nav>
</header>
I reduce the CSS part to this:
.hamburger {
display: none;
}
Is it appropriate to hide the .hamburger in the DOM? (I also gave it an area-expanded – does it make sense?)
The JS: Here I am primarily interested whether the if statement changing the area-expanded dynamically works as intended.
const hamburger = document.querySelector(".hamburger");
const navMenu = document.querySelector(".nav-menu");
hamburger.addEventListener("click", openMenu);
function openMenu() {
hamburger.classList.toggle("active");
navMenu.classList.toggle("active");
// Not sure whether, this is correct
if (navMenu.classList.contains("active")) {
hamburger.setAttribute("aria-expanded", "true");
} else {
hamburger.setAttribute("aria-expanded", "false");
}
}
It would be great, if:
you could provide feedback, which makes this menu more accessible.
you could give me an idea how to optimize the keyboard input.
you comment whether it is approppriate to hide the the hamburger with display: none
you could tell me whether the JS which dynamically changes the Boolean in area-expanded is correct.
Thank you for your time.

Related

.NET MAUI Blazor not rendering bottom of display for iOS

I am having some difficulty with a .NET MAUI Blazor project, I am not very familiar with the platform. The application in question was created from the template demo app created upon project setup in visual studio. (I am just testing this snippet to see if I can get it to work in isolation before adding it to the rest of my project). The issue I am having only seems to persist when running the application on iOS devices (The task bar is on the bottom of the screen on windows, Android and MacCatalyst). I am trying to create a task bar fixed to the bottom of the display. Upon launch the task bar is some distance from the bottom and I can't seem to override this to make it actually on the bottom. For some unknown reason the task bar does jump to the bottom of the display after you rotate the device 90 degrees and back. The project is unchanged from the template with the exception of the following code snippet pasted into the NavMenu.razor file:
<nav class="navbar navbar-expand fixed-bottom" style="background-color: beige">
<div class="container-fluid">
<div class="nav-item d-inline-flex">
<NavLink class="nav-link text-center" href="/">
<span class="oi oi-home"></span>
</NavLink>
</div>
<div class="nav-item d-inline-flex">
<NavLink class="nav-link text-center" href="search">
<span class="oi oi-magnifying-glass"></span>
</NavLink>
</div>
<div class="nav-item d-inline-flex">
<NavLink class="nav-link text-center" href="post">
<span class="oi oi-plus"></span>
</NavLink>
</div>
<div class="nav-item d-inline-flex">
<NavLink class="nav-link text-center" href="learn">
<span class="oi oi-bolt"></span>
</NavLink>
</div>
<div class="nav-item d-inline-flex">
<NavLink class="nav-link text-center" href="book">
<span class="oi oi-book"></span>
</NavLink>
</div>
</div>
</nav>
The project is using Bootstrap 5. The fixed-bottom tag does not seem to do anything (on iOS) as I understand it should. I have also tried putting this snippet directly in the MainLayout.razor in its own div and assigning the CSS properties manually, with little effect. I am familiar with the concept of safe-areas in iOS, but I have not been able to find a working solution to this problem.
Is there some property I am unaware of that allows you to properly assign something to the bottom of the screen?
I have tried using CSS to style the component with:
.mynav {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
with little effect. I also looked into webkit safe areas and The default project uses safe areas to prevent rendering overtop of things like the clock and such at the top of the screen, but I do not see any similar attribute to be causing this on the bottom.
It seems that the distance is due to the safearea in iOS. You could set safearea for iOS platform. Add the following code in your MainPage.xaml:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
....
BackgroundColor="{DynamicResource PageBackgroundColor}"
xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls"
ios:Page.UseSafeArea="True">
This reduce much of the distance from the bottom.
Hope my answer could help you.

Bootstrap collapse menu/dropdown menu color question

Good afternoon! I'm currently working on a navbar but the menu that pops up on from clicking on the hamburger icon (which shows all the links/navigation-items as a smaller screen widths) is a little too gaudy/not really good on a presentation level. How can I customize that dropdown menu to look better? HTML code is below:
<nav id="navigation" class="navbar navbar-expand-sm">
Brand
<button id="hamburger-icon" class="navbar-toggler" data-toggle="collapse" data-target="#collap-menu">
<span class="navbar-toggler-icon"><img src="D:\code\yannijewelry\images\evileyepng.png"></span>
</button>
<div id="collap-menu" class="collapse navbar-collapse">
<ul class="navbar-nav ml-auto">
<li><a class="nav-link" href="#">Etsy</a></li>
<li><a class="nav-link" href="#">Facebook</a></li>
<li><a class="nav-link" href="#">Instagram</a></li>
</ul>
</div>
</nav>
What element do I target, or rather, how can I customize a better dropdown menu? I noticed the hamburger icon, when clicked, also pushes the navbar elements up when it shows
Its hard to know exactly how to advise you on styling since we can't see exactly what styles you're currently viewing with just the HTML. Utilizing the core Bootstrap CSS, I can approximate your view and advise accordingly.
Let's say you want to change the background and text color of each of your menu items:
#collap-menu li{
background: #666;
padding-left: 20px;
}
#collap-menu li a{
color: #fff;
}
This would set your menu items to a gray background with white text with a little additional spacing for the text. You can replace the colors here with the branding colors of your website. Any changes beyond changing the text and color would need to be specifically outlined in your request.

Close navigation menu if page link is clicked

In my Angular 8 application, a fixed navigation bar exists on top of the screen. When a user hovers over a dropdown nav link, a menu will show up.
Now, if the user clicks on one of the menu links, the corresponding page will be opened using Angular Routing:
<div class="nav-left">
<div class="dropdown">
<a class="menu" routerLink="/home">
{{'HOME.TITLE' | translate}}
<span class="icon"><i class="fa fa-fw fa-angle-down"></i></span>
</a>
<div class="dropdown-content">
<a routerLink="/home/welcome">
<span class="icon"><i class="fa fa-fw fa-home"></i></span>
{{'HOME.TITLE' | translate}}
</a>
<a routerLink="/home/news-blog">
<span class="icon"><i class="fa fa-fw fa-newspaper-o"></i></span>
{{'HOME.NEWS_BLOG' | translate}}
</a>
<a routerLink="/home/features">
<span class="icon"><i class="fa fa-fw fa-cubes"></i></span>
{{'HOME.FEATURES' | translate}}
</a>
</div>
</div>
</div>
My SCSS definition has a .dropdown:hover selector that shows a menu only if it is hovered:
.dropdown {
.dropdown-content {
display: none;
}
&:hover {
.dropdown-content {
display: block;
}
}
}
What I would like to achieve is that the navigation menu closes automatically when the user clicks a menu link. Right now, the menu remains open because Angular Router does not reload the page but only replaces the page contents by the selected subpage.
In my opinion, there should be a pure CSS / SCSS solution to this problem, although it would be okay for me if it only works with some TypeScript code. My ideas have been so far:
use a special "click" or "selected" CSS selector to define display: none if a link has been clicked
activate some Angular function (if exists?) that resets the "CSS state" (as if the page would have been reloaded)
write a method to close all navigation menus when a routerLink has been clicked (seems too complicated)
Do you have any recommendations which of the mentioned approaches would fit best and how to realize it?
You could have a listener in your template along the lines of:
<div class="dropdown" [ngClass]="{'visible': menuVisible}" (mouseover)="toggleMenu()" (mouseout)="toggleMenu()">
And in your TS:
menuVisible = false;
toggleMenu() {
this.menuVisible = !this.menuVisible;
}
This would be a very simple implementation. You could also do it using Observables, for example (having a Subject emit for each mouse event).
EDIT: I totally forgot to add the click listener part haha! I think you got the idea though!

angular-bootstrap dropdown on mouseenter and keep dropdown-menu from hiding before being clicked.

First, I'm aware of this posts:
Activating bootstrap dropdown menu on hover
Bootstrap Dropdown with Hover
How to make twitter bootstrap menu dropdown on hover rather than click
And others, but still not found the correct solution yet, here's what I did so far.
first I used the is-open attribute from the angular-bootstrap dropdown directive like this:
<span class="dropdown" dropdown is-open="status.isopen">
<a
href
class="dropdown-toggle"
ng-mouseenter="status.isopen = true"
ng-mouseleave="status.isopen = false"
>
hover me for a dropdown with angular-bootstrap
</a>
<ul
class="dropdown-menu"
>
<li ng-repeat="choice in items">
<a href>{{choice}}</a>
</li>
</ul>
</span>
that seemed to work but 2 bugs appeared:
the first is when dropdown-toggle element is clicked the dropdown menu is gone clicking again wont bring it back you have to mouseleave then mouse enter the dropdown-tooggle to get the dropdown-menu back.
the second is a css/html problem.
Usually the regular css solution for a dropdown is like this:
<a class="css-dropdown">
hover here with css.
<div class="css-dropdown-menu">
<p>item 1</p>
<p>item 2</p>
<p>item 3</p>
</div>
</a>
Notice the dropdown-menu now is inside the dropdown-toggle element which mean when moving with the mouse from the dropdown-toggle to the dropdown-menu it's moving from parent to child, so basically we still hovering over the dropdown-toggle since we are in it's child, which mean the dropdown-menu will still be visible, on other hand, the bootstrap dropdown works with the click event so having the dropdown-menu as a child of the dropdown-toggle is not needed, but now when someone wants to change the behavior to mouseenter/hover once the mouse leaves the dropdown-toggle the dropdown-menu disappear so we no longer have access to the dropdown-menu elements this is visible in this plunker
To fix the first bug, I just removed the dropdown directive then replaced the is-open with ng-class directive like this.
Change this:
<span class="dropdown" dropdown is-open="status.isopen">
to this:
<span class="dropdown" ng-class="{'open': status.isopen}">
The rest stays the same plunker that fixed the first bug.
The second bug is tricky, since the dropdown-menu is no longer a child of the dropdown-toggle the hover effect wont last while moving from the toggle to the menu, so I did this.
Changed this:
<ul class="dropdown-menu">
to this:
<ul
class="dropdown-menu"
ng-mouseenter="status.isopen = true"
ng-mouseleave="status.isopen = false"
>
That did it but another bug appeared when clicking the dropdown-menu item it stays open, so I kept hacking by doing this.
changed this:
<li ng-repeat="choice in items">
to this:
<li ng-repeat="choice in items" ng-click="status.isopen = false">
That give me the required behavior plunker.
That said, this is not a good solution since a lot of directives are involved here for a simple visual effect, the last plunker I provided contains a css solution with no Bootstrap or AngularJS involved, though it is the required behavior it is not the required html structure or visual result, what I need is to have a space between the dropdown-toggle and the dropdown-menu not a padding of the toggle element just an empty space, which make the css solution not valid in this situation.
So, my question is there a better way of doing this without adding a new plugin/library more clean and easily reusable solution for the hover drop down menu?
First, have the toggling on the top-most parent element (in this case, the <span>)
<span class="btn-group" dropdown is-open="status.isopen" ng-mouseenter="status.isopen = true" ng-mouseleave="status.isopen = false">
<a class="btn btn-primary dropdown-toggle" dropdown-toggle>
Button dropdown <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li>Action</li>
<li>Another action</li>
<li>Something else here</li>
<li class="divider"></li>
<li>Separated link</li>
</ul>
</span>
This will allow the behavior you wanted - while still allowing clicking to show/hide the menu ;-)
However there's an annoyance: if you move the mouse cursor slower and pass the small gap between the toggle and menu, it will hide the menu.
So secondly, add a small CSS to remove the gap
.dropdown-menu {
margin-top: 0;
}
See the action in this plunker.
I know you want a solution without adding a new plugin/library, but you (or others seeking for this behavior) might want to try using No Close from Dropdown Enhancements lib to keep the dropdown open even after clicking in one of its options:
Do not close the menu on click on radio add class .noclose.
<div class="btn-group">
<button data-toggle="dropdown" class="btn btn-default dropdown-toggle">
Checked option <span class="caret"></span>
</button>
<ul class="dropdown-menu noclose">
<li>
<input type="radio" id="gr1_1" name="gr1" value="1">
<label for="gr1_1">Option 1</label>
</li>
<li>
<input type="radio" id="gr1_2" name="gr1" value="2">
<label for="gr1_2">Option 2</label>
</li>
<li>
<input type="radio" id="gr1_3" name="gr1" value="3">
<label for="gr1_3">Option 3</label>
</li>
</ul>
</div>
Also add a CSS solution for the hovering problem:
.btn-group:hover .dropdown-menu.noclose {
display: block;
}
.dropdown-menu.noclose {
margin-top: 0px;
}
And, of course, don't forget to import the libs:
<script src="./js/dropdowns-enhancement.min.js"></script>
<link href="./css/dropdowns-enhancement.css" rel="stylesheet"\>
In your case I suggest you to study the Dropdown Enhancements's source code to see how it works and maybe find a more suitable solution.
Try adding this line to your css:
.btn-group:hover>.dropdown-menu { display: block; margin-top: 0; }
You'll have to remove your is-open, ng-mouseenter and ng-mouseleave directives.
Below is the solution I came up with, while working on the same issue.
I used a simple custom directive that:
binds the mouseenter and mouseleave events to the dropdown in order correctly to show/hide the menu.
dynamically adds a custom CSS class to the dropdown menu in order to prevent the menu from disappearing when moving the cursor from the button to the menu. Note that this solution has the advantage of not removing the visual gap between the button and menu.
prevents the menu from disappearing when the button is clicked.
The CSS rule uses a before pseudo-element to fill the gap between the button and the menu. I added the border property which can be uncommented to easily get a visual feedback.
.dropdown-hover-menu::before {
content: '';
position: absolute;
left: 0;
width: 100%;
top: -3px;
height: 3px;
/*border: 1px solid black;*/
}
The HTML structure of the snippet is based on the available examples in the dropdown section of the angular-ui bootstrap documentation
angular.module('app', ['ui.bootstrap'])
.directive('dropdownHover', function() {
return {
require: 'uibDropdown',
link: function(scope, element, attrs, dropdownCtrl) {
var menu = angular.element(element[0].querySelector('.dropdown-menu')),
button = angular.element(element[0].querySelector('.dropdown-toggle'));
menu.addClass('dropdown-hover-menu');
element.bind('mouseenter', onMouseenter);
element.bind('mouseleave', onMouseleave);
button.bind('click', onClick);
function openDropdown(open) {
scope.$apply(function() {
dropdownCtrl.toggle(open);
});
}
function onMouseenter(event) {
if (!element.hasClass('disabled') && !attrs.disabled) {
openDropdown(true);
}
};
function onMouseleave(event) {
openDropdown(false);
};
function onClick(event) {
event.stopPropagation();
}
scope.$on('$destroy', function() {
element.unbind('mouseenter', onMouseenter);
element.unbind('mouseleave', onMouseleave);
button.unbind('click', onClick);
});
}
};
});
.dropdown-hover-menu::before {
content: '';
position: absolute;
left: 0;
width: 100%;
top: -3px;
height: 3px;
/*border: 1px solid black;*/
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.3.3/ui-bootstrap-tpls.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div ng-app="app">
<div class="btn-group" uib-dropdown dropdown-hover>
<button type="button" class="btn btn-primary dropdown-toggle">
Button dropdown <span class="caret"></span>
</button>
<ul class="dropdown-menu" uib-dropdown-menu role="menu">
<li role="menuitem">Action
</li>
<li role="menuitem">Another action
</li>
<li role="menuitem">Something else here
</li>
<li class="divider"></li>
<li role="menuitem">Separated link
</li>
</ul>
</div>
</div>

Turn header menu/navbar's texts turn into icons for small viewports (rails 4/bootstrap3)

I am using bootstrap 3 on a Rails 4 app.
I have a "normal" fixed navbar on the page headers. For the moment, when the viewport decreases (small device), all menu titles disappear and go into the "three bars" icon like here: http://getbootstrap.com/examples/navbar-fixed-top/ (try on a small screen/viewport).
Is it possible with bootstrap 3 to NOT make all menu titles go into this three bar icon, but to replace all texts by very small icons (for example Help would be replaced by a " ? "icon) so that there is enough space for all of them, when the viewport is very small.
Is there something already built-in inside Bootstrap allowing to do that ? or maybe some external libraries that play well with BS3?
thanks
That should not be to hard, and no need for a framework. You can use the responsive utility classes provided by BS3. With those, you can hide the icons on big screen and show the labels, and the opposite when on small screen. Your navbar markup would look something like this:
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<ul class="nav navbar-nav">
<li class="active"><a href="#">
<i class='glyphicon glyphicon-user visible-xs-inline-block'></i>
<span class='hidden-xs'>Link</span>
</a></li>
<li><a href="#">
<i class='glyphicon glyphicon-user visible-xs-inline-block'></i>
<span class='hidden-xs'>Link</span>
</a></li>
</ul>
</div>
</nav>
And a small line of css is required to prevent the li from being displayed as block on small screens. Something like this should do the trick:
.nav>li {
display: inline-block;
}
And an example to demonstrate: http://www.bootply.com/a17IsJ0Pop

Resources