Reset CSS hover dropdown with JQLite - html

I'm currently in a project developing an Angular SPA that has dropdown menus in its main navbar. To get this effect, we are using CSS: hover selectors. The issue is that when an action is performed within this dropdowns we would like to close them without hindering the ability to open them again. For example, if a user opens a link within one of this dropdowns (internal link with ui-sref) he is then taken to this particular state, but the dropdown would still be visible until he moves the mouse outside it (and partially obscuring the new content shown). We would like the dropdown to be closed when an action within is performed and if the user would like to open it again, he would be able to hover the mouse again over the trigger.
We tried removing and re-adding classes (even after a timeout) but the dropdown reappears again.
Link to a Plunker with a setup similar to what we are trying to accomplish: https://plnkr.co/edit/qzQk4r2WQFhwsgUWug39?p=preview
And the relevant portions (Angular controller omitted as it has no content):
HTML:
<div class="hoverable has-dropdown">
<button class="dropdown-trigger">Hover me!</button>
<div class="dropdown">
Dropdown content
<button ng-click="buttonAction()">Action</button>
</div>
</div>
CSS:
.dropdown {
display: none;
position: absolute;
top: 20px;
width: 100px;
height: 100px;
background: lightgrey;
padding: 1em;
}
.has-dropdown {
position: relative;
height: 20px;
}
.has-dropdown .dropdown-trigger:hover + .dropdown,
.has-dropdown .dropdown-trigger + .dropdown:hover {
display: block;
}
Thanks!

Finally solved it by using ng-mousenter and ng-mouseleave and dropping CSS :hover rules. As everything is based on JS I can just trigger mouseleave when I want to close them.

Related

Accessible nested button inside button?

I'm trying to build a button that looks like Zoom's button.
Here there is a button to pick a device inside the camera button. I'd like to create something similar, where you have a button and another button that expands a picker inside it.
How can you create this in an accessible way?
If I nest buttons in React, it throws errors that you can't nest a button inside another. Zoom's equivalent would be:
<button>
Stop Video
<button>Pick Device</button>
</button>
which doesn't work. How would you create an interface like this so it stays accessible (and valid)?
Preword
Don't nest interactive elements
There is a reason that it isn't valid HTML to nest buttons or hyperlinks, it causes nightmares for knowing which action should be performed on a click (for a start) and for assistive technology this makes things even worse as it can confuse the accessibility tree as to what it should present to screen readers.
The answer
If you look carefully you will see they aren't actually nested, the "picker" button is placed on top of the other button.
Now there is an issue here in terms of accessibility, click / tap target size.
A button / interactive element should be no less than 44px by 44px
So the Zoom example you gave fails this criteria. Additionally the tooltip that says "stop video" looks wrong if you have the picker selected as that should be the tooltip for the button that is currently hovered.
So how could we create an accessible version of what you want?
I would recommend having a large button with a 44 by 44 button placed on top to the right.
This can easily be done with absolute positioning.
To ensure that it is evident visually that the buttons are related I inset the second button by 2px.
The below is not a complete example but I have given you a start.
I added aria-expanded to the button that opens the sub menu, this gets toggled when the menu is opened.
I also added the aria-haspopup attribute to let users know that this button opens a sub menu.
I also added aria-controls to let assistive technology know the relationship between the button and the menu it opens.
Finally you will see I added a <span> with some visually hidden text inside so that screen reader users know that the picker button opens the video controls.
The example maintains logical tab order and is pretty accessible, but there are still things such as being able navigate the menu buttons with the arrow keys, closing the menu with Esc key and returning focus to the button that opened the menu etc. that you need to implement yourself. Oh and styling obviously!
var mainButton = document.querySelector('.main-button');
var menuToggle = document.querySelector('.sub-button');
var menu = document.getElementById('controls');
mainButton.addEventListener('click', function(){
alert("clicked the main button");
});
menuToggle.addEventListener('click', function(){
if(menu.classList.contains('open')){
menu.classList.remove('open');
menuToggle.setAttribute('aria-expanded', false);
}else{
menu.classList.add('open');
menuToggle.setAttribute('aria-expanded', true);
}
});
.container{
position: relative;
width: 144px;
height: 48px;
}
.main-button{
width: 144px;
height: 48px;
padding-right: 50px;
}
.sub-button{
position: absolute;
width: 44px;
height: 44px;
top:2px;
right:2px;
}
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
#controls{
display: none;
}
#controls.open{
display: block;
}
<div class="container">
<button class="main-button">Stop Video</button>
<button class="sub-button" aria-expanded="false" aria-haspopup="true" aria-controls="controls">⌄ <span class="visually-hidden">Pick Device</span></button>
<ul id="controls"
role="menu"
aria-labelledby="sub-button">
<li><button>Option 1</button></li>
<li><button>Option 2</button></li>
</ul>
</div>
The react gives a warning if you try to do so and the reason is simple. It has everything to do with semantic HTML and you should never put a button inside a button.
Alternatively to get the desired behaviour you can do something like this:
<div style={{ position: "relative", width: "200px", height: "40px" }}>
<button
onClick={() => console.log("Stop Video")}
style={{ width: "100%", height: "100%" }}
>
Stop Video
</button>
<button
onClick={() => console.log("Pick Device")}
style={{ position: "absolute", right: 0, top: 0 }}
>
Pick Device
</button>
</div>
This will do the same thing you need. Here is the codesandbox example for the same implementing the exact same thing.

Hover event converts to click on mobile except iPhone / Safari?

I'm a bit confused about this but I think I've found the issue.
I have in my html:
<div class="dropdownz">
<button>HOVER_OR_CLICK</button>
<div class="dropdownz-content">
</div>
</div>
In my css I have:
.dropdownz {
float: left;
overflow: hidden;
}
.dropdownz-content {
display: none;
position: absolute;
z-index: 1;
}
.dropdownz:hover .dropdownz-content {
display: block;
position: fixed;
top: 50px;
}
So this basically means if I hover over the dropdownz class, the dropdownz-content display converts from none to block and the menu items show.
When I run this on an android touchscreen mobile device, I have to CLICK the dropdownz item in order for it to effect the hover and show the list, if I click it again, it effectively removes the hover.
This is desirable behaviour, it means I don't have to do any extra stuff for touch-screens. A "hover" becomes a click and the 2nd click removes the "hover". Great!
Apparently this doesn't work the same in SAFARI on an iPhone. I can't test it myself, I'm going via a friend who says it's not working, so I basically want to know:
Is this a known issue and what's the best way to remedy it? (Without JavaScript, surely!)
I'm thinking along the lines of :focus ?
try this :
.dropdownz:hover .dropdownz-content,
.dropdownz:active .dropdownz-content,
.dropdownz:focus .dropdownz-content{
display: block;
position: fixed;
top: 50px;
}

Input:checked + aside, is it possible to target other elements?

In my html right now I have the label and input above the aside which I am trying to toggle like so:
<label for="hamburger"><img src="images/hamburger.png"></label>
<input type="checkbox" id="hamburger" />
<aside>
<!-- stuff -->
</aside>
<main>
<!-- stuff -->
</main>
To make things a little complicated, the hamburger only shows up once we reach a media query of max-width 768px like so:
#media(max-width:768px) {
aside {
margin: -335px;
}
main {
margin-left: 0;
}
label {
position: absolute;
top: 20px;
left: 25px;
width: 25px;
height: auto;
display: block;
cursor: pointer;
}
#hamburger:checked + aside {
margin: 0px;
}
}
So what happens is the aside gets pulled to the left, which makes it invisible, the main now fills the screen and its margin disappears and the label(#hamburger) shows up. When I click the newly appeared #hamburger it toggles back and forth between the aside showing up and not showing up. The problem I am having is this: I would like for the hamburger to move with the main section as I toggle back and forth, instead of sitting above the aside in the html. But if I move the label and checkbox inside the main I can't target the aside because #hamburger:checked + aside (for the + to work, I need to have it directly above it).
So the question is can I target other class with #hamburger:checked .class {}, because if I can, I cant seem to figure out how. If I cant do that how can I work around it?
I am sorry for the long winded question but I wanted to make sure I'm thorough in explaining my problem.

pop up modal not working properly

i am making a website for my college as a project.To show you i have hosted the same on a free
hosting site. link http://vivace.net23.net/ .Now in the informal section of menu i wanted to put a pop up modal here is the fiddle..http://jsfiddle.net/karn21/73QXx/.
Click Me
<div id="openModal" class="modalDialog">
<div>
X
</div>
</div>
But on click it is not working.Please help me
Instead of setting it as a target, you could set an onclick event for the Click Me button that triggers a JavaScript function to append the id target to the div (or another class). Then, change .modalDialog:target to .modalDialog.target. Then, just remove the class when the close button is clicked.
New Fiddle: http://jsfiddle.net/73QXx/2/
That shouldn't interfere with your hastag scrolling script.
Also, if you still wanted it to appear as a link, you can add this:
CSS:
a {
color: #0645AD;
text-decoration: underline;
cursor: hand;
cursor: pointer;
}
a:visited {
color: #663366;
}
EDIT:
This line is only supported by IE11+:
pointer-events: none;
Here is an alternative that you can add using an HTML IF to check if the version is IE10 or less:
pointer-events: none; => z-index: -1;
pointer-events: auto; => z-index: 10; /*This may need to be increased depending
on the elements on the page*/
New Fiddle for IE9 (and many other versions including anything that the old version can support): http://jsfiddle.net/73QXx/3/
However, the downside and why this should not be used for anything except IE9 or lower (which is possible with HTML IF) is that the box suddenly appears instead of fading in.

Use Only CSS to Alter Various Elements

I have a page with a left sidebar that I want to be able to toggle on or off based on whether or not the user clicks it. Unfortunately entering JavaScript code on this website has been disabled and I only have access to CSS.
The left sidebar has
its main div (parentBlock)
a div for the show/hide, (toggleBlock)
a div for the logo, (div1)
a div for the navbar, and (div2)
a div for social icons (div2)
When the user clicks on "Show / Hide" I want to:
Hide (display:none) the logo, navbar, and social div's, and
Set the height of the main div to something smaller (say 30px).
Is there any way to do this in CSS?
<div class="parentBlock">
<div class="toggleBlock">Show / Hide</div>
<div class="divBlah">div1</div>
<div class="divBlah">div2</div>
<div class="divBlah">div3</div>
</div>
Then if the user clicks "Show / Hide" again, it will unhide the div's and set the height back to filling the screen.
Is this possible?
I found some code that would work if the "Show / Hide" button was in "parentBlock" but it didn't work if it was within "toggleBlock" (and I have to have the Show/Hide button in toggleBlock)
(http://tympanus.net/codrops/2012/12/17/css-click-events/)
I realize onClick events require JavaScript. Those are not possible since I can't use JavaScript :( Some people try to get around it by using either :active or creating checkboxes and having the checkbox:clicked value load the action ... but it only works with certain relations that I can't seem to nail down.
Unfortunately I cannot alter the ultimate structure of "toggleBlock", div1, div2, and div3 ... only what's in them and their CSS. Also making it even more difficult is that the website randomly generates ID="" each time the page loads so the TARGET method isn't possible. Also, the 3 div's (div1 thru div3) have the same class name. I'm beginning to think it's impossible :(
(For reference, I'm trying to use the tools on the New SmugMug and they're rather restrictive)
Here is a CSS only solution using target
DEMO http://jsfiddle.net/kevinPHPkevin/r4AQd/
.button {
display: block;
width:60px;
background: red;
z-index:1;
}
#element {
display: none;
background:#fff;
margin-top:-20px;
z-index:2;
}
#element:target {
display: block;
}
#show:target {
display: block;
}
#hide {
background: #000;
color: #fff;
}
As Joum has pointed out this is not possible to do via click events but using hover on siblings you might be able to achieve a similar effect. for example try adding this css:
div.toggleBlock { display: block; }
div.toggleBlock ~ div { display: none; }
div.toggleBlock:hover ~ div { display: block; }
for more information see this: http://css-tricks.com/child-and-sibling-selectors/