Highlighting an element with allowed interaction - javascript

I'm trying to create my own product tour handling (after trying some like intro.js).
Here is a JSFiddle that I've just created.
What I have is a div with CSS:
.highlight {
position: fixed;
top: 14px;
left: 16px;
width: 54px;
height: 40px;
z-index: 1000;
pointer-events: none;
}
.highlight__overlay {
width: 100%;
height: 100%;
position: absolute;
z-index: 12;
top: 0;
left: 0;
border-radius: 5px;
transition: all .5s ease;
border: 2000px solid rgba(0 ,0 ,0 ,0.85);
margin: -1000px;
box-sizing: content-box;
transform: translate3d(-1000px, -1000px, 0);
pointer-events: none;
}
As you can see, the button is highlighted, and clickable, but other two button can also be clicked.
How can I make only the element in the highlighted area clickable?
Also - are there any product tour/tutorial JS libraries that I should be aware of? Those, that will basically have the functionality that I need.

I have updated your jsfiddle Here
I added pointer-events: none to the button section of your css and gave button One a class of enabledButton.
Then I added pointer-events: auto to the .enabledButton section of your css
With a single line of jquery you can remove the enabledButton class from all buttons:
$("button").removeClass("enabledButton");
You then add the enabledButton class only to the button you highlight.
Now, the button with the class of enabledButton will be clickable while all others are not. This way you explicitly enable the button you want the user to click while all other buttons are disabled by default.

You can use css to do something like
. disabled{
pointer-events : none;
}
And add this class to the other non-highlighted buttons.
Another solution that requires some Javascript, is to add a default Html disabled attribute to your buttons, and remove it only for the highlighted button using innerHTML of something similar.

Related

How can I toggle or hide CSS pseudo-elements on event (e.g., click)?

Background
I have an HTML div which contains a ‘tooltip’-like feature (i.e., a text box pops up when a certain element is clicked or hovered over); this tooltip has decorative pseudo-elements to make it look like a ‘speech bubble,’ added in css as :before and :after .
I have a JS script, which is intended to show and hide the tooltip and decoration, in response to click events (i.e., toggle them between ‘show’ and ‘hide’ states).
Problem
I can’t get the decorative pseudo-elements to hide when the tooltip is hidden; as pseudo-elements, they are not part of the DOM and so I can’t use normal selectors to manipulate them.
When the tooltip is hidden on click, the decorative pseudo-elements persist, which is not a usable result.
I can’t do away with the decorative elements, they are part of the work specification.
Approach tried so far
Based on this question, my thought was to add an empty span with its own class, to which I’d prepend and append these pseudo-elements. Then, add or remove the class on click based on whether it exists already, or not.
I have also tried setting the class to which the pseudo-elements are pre/appended to display:none on click, but this also seems not to work
However, I cannot convince the pseudo-elements to hide on click.
I’ve included a screenshot of what these remnant pseudo-elements look like in the live environment.
Note: I tried to work up a running simulation for the purpose of this question, but I wasn’t able to and the original css file is massive; the code included below is for reference only.
All guidance is much appreciated!
const barContainer = document.querySelector(".bar-container");
const decorationElement = document.querySelector("#decoration");
document.addEventListener('click', function(event) {
console.log('click event listener triggered');
if (event.target.closest('.link') || event.target.classList.contains('link')) {
if (barContainer.classList.contains('open')) {
barContainer.classList.remove('open')
decorationElement.classList.remove('decoration')
document.querySelector('.tooltip-container').setAttribute('style', 'display:none');
} else {
barContainer.classList.add('open')
decorationElement.classList.add('decoration')
document.querySelector('.tooltip-container').setAttribute('style', 'display:block');
}
} else {
barContainer.classList.remove('open')
decorationElement.classList.remove('decoration')
document.querySelector('.tooltip-container').setAttribute('style', 'display:none');
}
});
.foo-container {
height: auto;
position: relative;
}
.bar-container {
height: auto;
position: relative;
text-align: center;
}
.bar-container:hover .tooltip-container,
.tooltip-container:hover,
.bar-container.open .tooltip-container {
position: absolute;
display: block;
text-align: left;
background-color: #ffffff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
bottom: 50px;
right: 5%;
border-radius: 4%;
font-weight: 300;
max-width: 90%;
font-size: 14px;
padding: 20px 0;
}
/*the below two rule sets create the rotated 'decoration' */
.bar-container:hover .tooltip-container:before,
.tooltip-container:hover:before,
.bar-container.open .tooltip-container:before,
.foo-container .bar-container:hover .decoration:before {
content: "";
width: 65px;
height: 35px;
position: absolute;
overflow: hidden;
transform: rotate(-180deg);
z-index: 10;
bottom: 0;
left: 170px;
background-color: white;
}
.foo-container .bar-container.open .decoration:before,
.foo-container .bar-container:hover .decoration:before {
content: "";
position: absolute;
width: 30px;
height: 30px;
background: #fff;
transform: rotate(45deg);
left: 30px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
z-index: 2;
top: -42px;
}
/* end 'deocration' */
<div class="foo-container">
<div class="bar-container">
<p>text <span class='link'>the-link<span id='decoration' class='decoration'></span></span>
</p>
<div class='tooltip-container'>
<p>lorem </p>
</div>
</div>
</div>
Screenshot of the undesirable 'persistent pseudo-elements' behavior -->

Button behind text only on mobile

I am trying to do a very simple quiz like this one:
https://www.sitepoint.com/simple-javascript-quiz/
I tried to make it more responsive and added this line:
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1.0"/>
It worked fine but when I add a long text on the alternatives of each question, the button "Next Question" stay behind the text, only on mobile (iphone 6, safari).
I tried to add a z-index: 1000; and nothing changed:
button{
font-family: 'Work Sans', sans-serif;
font-size: 22px;
background-color: #279;
color: #fff;
border: 0px;
border-radius: 3px;
padding: 20px;
cursor: pointer;
margin-bottom: 20px;
z-index:1000;
}
So, there's a few things wrong here. As said above you need to remove the height from .quiz-container and remove the absolute positioning from .slide.
What I would suggest is that you add display: none; to slide then your active style to display:block - this will correctly display the button where it should be. With that said, you will lose the fade effect. You'd need to add this CSS to get it back. Hope this helps!
.quiz-container {
position: relative;
margin-top: 40px;
}
.slide {
width: 100%;
opacity: 0;
display: none;
}
.active-slide {
opacity: 1;
display: block;
}
You set position: absolute to your quizz questions, so they will ignore the space of every element you set in HTML.
A large z-index will only put an element above another, that's the why you see the quizz questions above the button.
The problem will be solved if you increment the height of quiz-container on mobile screen (try use #media screen).
https://www.w3schools.com/cssref/css3_pr_mediaquery.asp
I recomend you to find another way to put your questions at the top of page instead using position: absolute
The problem really is that your quiz-container div has a fixed height of 200px, and you can't make it fluid because your slides have position:absolute, which removes them from the flow and prevents the parent growing in height accordingly.
So you need to re-think how to go about this.
An interesting approach would be to use flexbox, controlling which slide to show with the order property.
.quiz-container {
margin-top: 40px;
overflow: hidden;
}
#quiz{
display: flex;
}
.slide {
opacity: 0;
transition: opacity 0.5s;
/*gives each slide 100% width and prevents it from growing or shrinking*/
flex: 0 0 100%;
}
.active-slide {
opacity: 1;
/*sets the order to -1, so it's positioned before all other flex-items*/
order: -1;
}

Show hover menu on tab key press

On this website, I have images that you can hover over with your mouse and it will display two buttons. I want keyboard-only users to be able to tab through the site, so when they tab, the hoverable menu shows up. I've read a lot of solutions involving :focus and tabindex=0 but I can't seem to make it work. I have attempted to put tabindex=0 on the <a> tags to see if that would do it, but it doesn't. I believe the buttons will be tabbed through just fine if I could just get the hover menu to show up using the tab key. I might be missing something obvious, but I'm a beginner with all of these things. If it's not possible via CSS, can someone suggest a JS solution?
HTML
<div class="thumbnail thumbnail-medium-short">
<div class="nqspCover-container">
<img src="img/stuff.jpg" alt="Front cover" width="180px" height="233px">
<div class="overlay">
<div class="read-button">Read</div>
<div class="buy-button">Buy</div>
</div>
</div>
<div class="nqsp-caption">
<p>stuff</p>
</div>
</div>
CSS
.nqspCover-container {
position: relative;
width: 180px;
height: 233px;
margin: 0 auto;
}
.overlay {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0);
transition: background 0.5s ease;
}
.nqspCover-container:hover .overlay {
background: rgba(0,0,0,.3);
}
.buy-button{
margin-top: 40px;
}
.read-button, .buy-button{
position: absolute;
width: 65px;
padding: 5px 15px;
border: solid 2px white;
opacity: 0;
transition: opacity .35s ease;
}
.read-button a, .buy-button a{
text-decoration: none;
text-align: center;
color: white;
}
.nqspCover-container:hover .read-button,
.nqspCover-container:hover .buy-button{
opacity: 1;
}
.read-button a:hover, .buy-button a:hover{
text-decoration: underline;
}
.read_button a:focus, .buy-button a:focus{
display: block;
}
Example of the hover menu I need to pop up when they tab to it (don't worry, the background img and buttons definitely won't look like that when it's done):
Only one element can have focus at a time, so you can not do this using :focus alone. That's what the :focus-within pseudo class was made to solve - but be aware of browser compatibility; MicroSofts two current browsers don't support it yet.
You'll need a JS solution or at least a polyfill for :focus-within
(FYI, div elements can't receive focus by default, so you'd need to start by adding the tabindex attribute. tabindex="0" is usually what you want to make an element focus-able in normal DOM order.)
I don't know if "focus" really does what I need it to do at all.
It does what the other pseudo classes do, too - no more or less: Identify/react to an element being in a specific state. What you do with it, or it's descendants/siblings, is up to you - by writing the selectors that target those elements, based on that parent/siblings state.
https://www.google.com/search?q=menu+with+focus-within gets you more detailed explanations & examples, f.e. http://www.scottohara.me/blog/2017/05/14/focus-within.html That one explains the topic pretty well, and also mentions a polyfill, https://allyjs.io/api/style/focus-within.html

Emulate CSS hover:before and hover:after behavior tooltips for touchscreens

I have a very nice CSS-only hover tooltip solution like so:
Works great on non-touchscreens but on touchscreens a click shows the tip and it never hides. I am trying to get a toggling solution which keeps the work I have done and adds a touchscreen jQuery or CSS solution to show and hide the tooltips. I'd like to have the show/hide toggle on click but a solution with delay() would also do.
I have read
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using jQuery
Access the css ":after" selector with jQuery
How to modify programmatically with javascript the css ::before and ::after
Here is the current code
JS added today to try to resolve for touchscreens:
$('.tooltip').click(function() {
$(this).addClass('tooltipBefore tooltipAfter').delay( 800 ).removeClass('tooltipBefore tooltipAfter');
});
HTML
<a href="#" class="tooltip" title="Putts per round is the average number of putts per round played." >
<span title="Info"><img src="/g/inputs/help.png"></span>
</a>
CSS - modified today to add .tooltipBefore .tooltipAfter which I also tried with :before and :after selectors added
.tooltip{
display: inline;
position: relative;
background:none;
border:none;
}
.tooltip:hover:after, .tooltipAfter:after {
background: #333;
background: rgba(0,0,0,.8);
border-radius: 5px;
bottom: 26px;
color: #fff;
content: attr(title);
left: 20%;
padding: 5px 15px;
position: absolute;
z-index: 98;
width: 220px;
}
.tooltip:hover:before, .tooltipBefore:before{
border: solid;
border-color: #333 transparent;
border-width: 6px 6px 0 6px;
bottom: 20px;
content: "";
left: 50%;
position: absolute;
z-index: 99;
}
EDIT 2
Revised JS per #maioman answer to below. Console log i verifying that the correct element is being selected by $(this) but in Chrome inspector the class flashes but is never modified by addClass or removeClass. Also tried toggleClass but class is not added.
END EDIT 2
console.log($(this).attr("Title"));
$(this).addClass('tooltipBefore').addClass('tooltipAfter').delay( 3000 ).removeClass('tooltipBefore').removeClass('tooltipAfter');
EDIT 3
OK, so edit #2 has issues with how I call the addClass and removeClass. This version works in browser but and toggles class correctly but still does not work on phone:
$('.tooltip').bind( "click touchstart", function() {
$(this).toggleClass('tooltipBefore tooltipAfter');
});
END EDIT 3
try changing this
$('.tooltip').click( function () {
to
$('.tooltip').on('click touchstart', function () {

How to "change" input type file style

(Read down the edit)
So I have been trying to do this a lot and I can't figure it out.
FIRST: the fiddle
http://jsfiddle.net/2RHfL/
What I want to do is to "change" the style of a input type="file". So what I did was to set it's opacity: 0 and then try to make it so that if fits entirely his parent div, so that when the user clicks at any part of the parent div, the input will be clicked (I can't do this via javascript, because I also want the user to drag & drop files to input). I can't change the input to an upload manager though javascript, I must do this trough the input tag.
I know the css is a little big, but the important stuff are the last two rules only, that modify the input & form css style:
.ux-hotels-reviews-upload .formAddDoc {
position: absolute;
overflow: hidden;
height: 100%;
width: 100%;
cursor: pointer;
}
.ux-hotels-reviews-upload .formAddDoc .inputFile {
position: absolute;
cursor: pointer;
/*opacity: 0;*/
/* font-size: 10000px;
border: 10000px solid transparent;
right: -1000px;
top: -1000px;*/
}
So, what I want is: If the user clicks/drops a file at the parent div (.ux-hotels-reviews-upload) make the click/drop to the input, but the input has to have his opacity to 0 and the items inside the div should look as they do now. (You can see that the opacity:0 rule is commented just for testing reasons).
If I forgot to mention something, tell me.
EDIT:
I've made a new fiddle so that it is more readble and easy to understand my problem, also I think I am a bit closer to the solution:
http://jsfiddle.net/fLfce/
So as you can see, if the FORM is with position: relative, then if fits perfectly the div (what I want) but the thext goes out of the div, si if I put position: absolute to the form, then the text goes exactly where I want but the FORM gets bigger (much more than the div).
What I want is: The form to be position: absolute and keep it's width and height to the 100% of the div, not more, not less.
form {
position: absolute;
border: 1px solid blue;
width: 100%;
height: 100%;
}
input {
border: 1px solid blue;
width: 100%;
height: 100%;
}
If I understood correctly what you want to do then you have to use negative margins with positive padding and a z-index on the .ux-hotels-reviews-upload .formAddDoc .inputFile file.
Like this:
.ux-hotels-reviews-upload .formAddDoc .inputFile {
cursor: pointer;
margin: -30%;
opacity: 0;
padding: 31%;
position: absolute;
z-index: 9999;
}
You need to 'fine-tune' the margin and padding to fit the div container.
http://jsfiddle.net/2RHfL/5/
Border is a bit off, but the effect that you wanted is there. Your HTML & CSS was very hard to read & messy, I suggest going through some refactoring.
input[type=file]{
opacity: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
color: white;
z-index: 10;
}
What I would do is wrap the area you want to show as a label, pointing to the file input, like this:
<label for="uploadPictureInput">
This will activate the file input when you interact with it (you could even replace your "ux-hotels-reviews-upload-info" div with it).
Though I think you still have to use javascript for drag&drop to work.
<input type="file" name="file" id="file" style="display:none"/>
<div onclick="file.click()" ondragdrop="file.dragdrop()">Text</div>
The <div> acts like the parent div that you mentionned but doesn't contain the file input which isn't displayed because of style="display:none".

Categories