Best practice for a button with image and text in mobile website - javascript

Refer to the screenshot below, I have created a div to wrap another two div of image and text, then I use CSS position: absolute to make these div merge together.
However, I found that the button is not sensitive while testing on mobile devices, sometime I need to touch the button few time to take effect.
So, is there something wrong for my code and what is the best practice to create a button with image and text?
Thanks
<div class="r">
<div class="a">
<div class="i"><img src="store_btn_on.png" /></div>
<div class="t">Shatin</div>
</div>
<div class="b">
<div class="i"><img src="store_btn_off.png" /></div>
<div class="t">Causeway Bay</div>
</div>
<div class="c">
<div class="i"><img src="store_btn_off.png" /></div>
<div class="t">Kowloon Bay</div>
</div>
</div>
Update for the part of javascript
addButtonListener($("#store > .r > .a"), function(event, target){
$("#some_content").css("display", "none");
$("#other_content").css("display", "block");
$(".r > .b > .a > img").attr("src" , "store_btn_on.png");
$(".r > .b > .b > img, .r > .b > .c > img").attr("src" , "store_btn_off.png");
});
function addButtonListener(targets, job){
if ("ontouchstart" in document.documentElement){
targets.each(function(){
$(this)[0].addEventListener('touchstart', function(event){
event.preventDefault();
$(this).attr({ "x": event.targetTouches[0].clientX, "diffX": 0, "y": event.targetTouches[0].clientY, "diffY": 0 });
$(this).addClass("on");
}, false);
$(this)[0].addEventListener('touchmove', function(event){
$(this).attr({
"diffX": Math.abs(event.targetTouches[0].clientX - $(this).attr("x")),
"diffY": Math.abs(event.targetTouches[0].clientY - $(this).attr("y"))
});
}, false);
$(this)[0].addEventListener("touchend", function(event){
$(this).removeClass("on");
if ($(this).attr("diffX") < 5 && $(this).attr("diffY") < 5){ $(job(event, $(this))); }
}, false);
});
}
else {
targets.each(function(){
$(this).mousedown(function(event){ event.preventDefault(); $(this).addClass("on"); });
$(this).mouseup(function(event){ event.preventDefault(); if ($(this).hasClass("on")){ $(job(event, $(this))); } $(this).removeClass("on"); });
$(this).hover(function(event){ $(this).removeClass("on"); });
});
}
}

I am not sure about the sensitivity of your button on mobile devices (you haven't shown any of your code for handling click events), but I think it is better to write your HTML like this:
<div class="r">
<div class="button on">
<span>Shatin</span>
</div>
<div class="button">
<span>Bay</span>
</div>
<div class="button">
<span>Bay</span>
</div>
</div>
Then use CSS in your stylesheet:
.button {
background: url(http://domain.com/images/store_btn_off.png) no-repeat 0 0;
/* Additional button styles */
}
.button.on {
background: url(http://domain.com/images/store_btn_on.png) no-repeat 0 0;
}
.button span {
color: #FFF;
margin: auto;
}
This makes it easy to dynamically turn a button on or off just by adding or removing the on class.
Although not necessary, you may also be interested in looking at CSS3 gradients to create simple gradient background images like that, and then degrade nicely to an image in browsers without any gradient support.
The class names "r" and "b" are not very descriptive. Unless some HTML/CSS minifier put those there and you have proper names in your development code, I would consider giving your classes more descriptive names as well.

Related

How to call different functions when scrolled using JavaScript?

I was trying to call different functions using JavaScript when a key is pressed. It worked perfectly! How can I achieve the same effect by using the scroll wheel?
The goal is to change the background image of the webpage, carry out a query in a SQL Table and store the x and y co ordinates of the pointer in a table.
Hope this can help :)
$(document).scroll(()=>{
if($(document).scrollTop() >= 970){
//If you want to get style permenent remove line below
$("body").css("background","red");
}
else if($(document).scrollTop() >= 508){
//If you want to get style permenent remove line below
$("body").css("background","blue");
}
else if($(document).scrollTop() >= 8){
//If you want to get style permenent remove line below
$("body").css("background","indigo");
}
})
/*This is for smooth scrolling*/
html {
scroll-behavior: smooth;
}
.big {
height: 500px;
width: 100%;
border: solid black 1px;
}
.active {
color:red;
}
<div id="main">
<div class="big" id ="home">Home</div>
<div class="big" id ="about">About Us</div>
<div class="big" id ="contacts">Contacts</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
You're looking at the onscroll and scroll event.
<div onscroll="myFunction()"></div>
or
document.getElementById("myDIV").addEventListener("scroll", myFunction);
or
document.getElementById("myDIV").onscroll = function() {myFunction()};
and add the function in all cases:
function myFunction() {
console.log("It works");
}
https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onscroll
https://www.w3schools.com/jsref/event_onscroll.asp

Javascript - show a button inside of a DIV when clicked (and hide all others)

I have a list of DIVS that have buttons inside. By default, all buttons are hidden. When I click within a DIV area, the current button inside of this clicked DIV are should show (class='.db') AND all previously clicked/shown buttons should be hidden (class='.dn'). In other words, at any time there should be only one button (currently clicked) shown and all other should be hidden.
I want to use vanilla Javascript and tried this below, but it won't work. I feel there is some small error but don't know where.. Note - the DIVS and buttons don't have their own unique IDs (they only have the same CSS (.posted) classes.
PS - maybe it'd be better not to add this onClick="t();" to each DIV and use an 'addEventListener' function, but this is way too much for me ; )
CSS:
.dn {display:none}
.db {display:block}
.posted {
height: 50px;
width: 100px;
background-color: green;
border: 2px solid red;
}
HTML:
<div class="posted" onClick="t();">
<button class="dn">Reply</button>
</div>
<div class="posted" onClick="t();">
<button class="dn">Reply</button>
</div>
<div class="posted" onClick="t();">
<button class="dn">Reply</button>
</div>
JAVASCRIPT:
function t()
{
var x=document.getElementsByClassName("posted"),i,y=document.getElementsByTagName("button");
for(i=0;i<x.length;i++)
{
x[i].y[0].className="dn";
};
x.y[0].className='db';//make sure the currently clicked DIV shows this button (?)
}
You might want to read more about selector, how to select class, block level etc.
some link might be helpful:
CSS selector:
https://www.w3schools.com/cssref/css_selectors.asp
jQuery selector:
https://api.jquery.com/category/selectors/
Solution - Using jQuery:
$('.posted').on('click', function() {
//find all class called posted with child called dn, then hide them all
$('.posted .dn').hide();
//find this clicked div, find a child called dn and show it
$(this).find('.dn').show();
});
.dn {
display: none
}
.db {
display: block
}
.posted {
height: 50px;
width: 100px;
background-color: green;
border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="posted">
<button class="dn">Reply1</button>
</div>
<div class="posted">
<button class="dn">Reply2</button>
</div>
<div class="posted">
<button class="dn">Reply3</button>
</div>
Solution - Pure js version:
//get list of div block with class="posted"
var divlist = Array.prototype.slice.call(document.getElementsByClassName('posted'));
//for each div
divlist.forEach(function(item) {
//add click event for this div
item.addEventListener("click", function() {
//hide all button first
divlist.forEach(function(el) {
el.getElementsByTagName('button')[0].classList.add('dn');
});
//show button of the div clicked
this.getElementsByTagName('button')[0].classList.remove('dn');
}, false);
});
.dn {
display: none
}
.db {
display: block
}
.posted {
height: 50px;
width: 100px;
background-color: green;
border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="posted">
<button class="dn">Reply1</button>
</div>
<div class="posted">
<button class="dn">Reply2</button>
</div>
<div class="posted">
<button class="dn">Reply3</button>
</div>
You can do this with with plain JavaScript using Event Bubbling, querySelector and the element classList attribute like this.
Change your HTML to look like this:
<div class="posts">
<div class="posted">
<button class="dn">Reply</button>
</div>
<div class="posted" >
<button class="dn">Reply</button>
</div>
<div class="posted" >
<button class="dn">Reply</button>
</div>
</div>
Then use JavaScript like this:
var posts = document.querySelector('.posts');
var allPosted = document.querySelectorAll('.posted');
//clicks bubble up into the posts DIV
posts.addEventListener('click', function(evt){
var divClickedIn = evt.target;
//hide all the buttons
allPosted.forEach(function(posted){
var postedBtn = posted.querySelector('button');
postedBtn.classList.remove('db');
});
// show the button in the clicked DIV
divClickedIn.querySelector('button').classList.add('db')
});
You can find a working example here: http://output.jsbin.com/saroyit
Here is very simple example using jQuery .siblings method:
$(function () {
$('.posted').click(function () {
$('button', this).show();
$(this).siblings().find('button').hide();
});
});
https://jsfiddle.net/3tg6o1q7/

combine two sets of floats on click

I have a folio page. When a user clicks link 'design' - all the relevant design images are shown. When the user clicks 'art' all the relevant art images are shown
What I would like to have is an 'all' button which combines them all.
The two sets are contained in divs which turn on and off perfectly in the below javascript. What I need is to add to the script so there is a function that says - click all and display both, instead of one or the other.
When have them both turned on, they flow into each other fine so thats not an issue. I'll keep the code as brief as I can. I have only icluded one image in each section but there is actually 6-7.
Thanks in advance!
my html is:
<div class="sectiondivider">
<div id="ThumbLinks">
ALL
ART<br />
GD
</div>
</div>
<div class="thumb_container">
<div class="thumbs" id="gd_info">
<div class="flex_one">
<img class="icon-image" src="gd.jpg"/>
</div>
</div>
<div class="thumbs" id="art_info">
<div class="flex_one">
<img class="icon-image" src="art.jpg"/>
</div>
</div>
</div>
CSS:
.gd_thumbs {
display:none;
}
.art_thumbs {
display:none;
}
.icon-image {
width:100%;
height:auto;
opacity:1;
}
.flex_one {
width:28%;
float:left;
position:relative;
background-color:#000;
border: solid 2px rgb(0,81,88);
overflow:hidden;
margin-left:4%;
margin-top:4%;
}
Javascript
$('#ThumbLinks a').click(function(e) {
// do something fancy
return false; // prevent default click action from happening!
e.preventDefault(); // same thing as above
});
$(document).ready(function(){
$("div.thumbs:gt(0)").hide(); // to hide all div except for the first one
$('#ThumbLinks a').click(function(selected) {
var getID = $(this).attr("id");
var projectImages = $(this).attr("name");
$("div.thumbs").hide();
$("#" + getID + "_info" ).fadeIn( "slow" );
});
});
Try this snippet.
It just checks if the link's id is all to show them all and, if not, keeps on with your old code. I tried to keep it as short as possible.
EDIT: I think the effect is nicer if, first of all, you hide them all
$('#ThumbLinks a').click(function(e) {
// first we hide them all (for a nicer effect)
$("div.thumbs").hide();
if ($(this).attr("id") == "all")
// if the ThumbLink's id is 'all' we fade in all the divs
$(".thumbs").fadeIn("slow");
else
// if not, we fade in just the correct one
$("#" + $(this).attr("id") + "_info").fadeIn("slow");
});
$(document).ready(function() {
$("div.thumbs:gt(0)").hide(); // hide all div except for the first one
$('#ThumbLinks a').click(function(e) {
// fisrt we hide them all (for a nicer effect)
$("div.thumbs").hide();
if ($(this).attr("id") == "all")
// if the ThumbLink's id is 'all' fade in all the divs
$(".thumbs").fadeIn("slow");
else
// if not, we fade in just the correct one
$("#" + $(this).attr("id") + "_info").fadeIn("slow");
});
});
.thumbs {
color: white;
}
.gd_thumbs {
display: none;
}
.art_thumbs {
display: none;
}
.icon-image {
width: 100%;
height: auto;
opacity: 1;
}
.flex_one {
width: 28%;
float: left;
position: relative;
background-color: #000;
border: solid 2px rgb(0, 81, 88);
overflow: hidden;
margin-left: 4%;
margin-top: 4%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="sectiondivider">
<div id="ThumbLinks">
ALL
ART
<br />
GD
</div>
</div>
<div class="thumb_container">
<div class="thumbs" id="gd_info">
<div class="flex_one">
I'm the GD div
<img class="icon-image" src="gd.jpg" />
</div>
</div>
<div class="thumbs" id="art_info">
<div class="flex_one">
I'm the ART div
<img class="icon-image" src="art.jpg" />
</div>
</div>
</div>

JQuery show and hide div on mouse click (animate)

This is my HTML code:
<div id="showmenu">Click Here</div>
<div class="menu" style="display: none;">
<ul>
<li>Button1</li>
<li>Button2</li>
<li>Button3</li>
</ul>
</div>
And I want to show .menu on click on #showmenu sliding from left to right (with animate). On click again on #showmenu or anywhere in site page, .menu will hide (slide back to left).
I use JQuery 2.0.3
I've tried this, but it doesn't do what I want.
$(document).ready(function() {
$('#showmenu').toggle(
function() {
$('.menu').slideDown("fast");
},
function() {
$('.menu').slideUp("fast");
}
);
});
That .toggle() method was removed from jQuery in version 1.9. You can do this instead:
$(document).ready(function() {
$('#showmenu').click(function() {
$('.menu').slideToggle("fast");
});
});
Demo: http://jsfiddle.net/APA2S/1/
...but as with the code in your question that would slide up or down. To slide left or right you can do the following:
$(document).ready(function() {
$('#showmenu').click(function() {
$('.menu').toggle("slide");
});
});
Demo: http://jsfiddle.net/APA2S/2/
Noting that this requires jQuery-UI's slide effect, but you added that tag to your question so I assume that is OK.
Of course slideDown and slideUp don't do what you want, you said you want it to be left/right, not top/down.
If your edit to your question adding the jquery-ui tag means you're using jQuery UI, I'd go with nnnnnn's solution, using jQuery UI's slide effect.
If not:
Assuming the menu starts out visible (edit: oops, I see that isn't a valid assumption; see note below), if you want it to slide out to the left and then later slide back in from the left, you could do this: Live Example | Live Source
$(document).ready(function() {
// Hide menu once we know its width
$('#showmenu').click(function() {
var $menu = $('.menu');
if ($menu.is(':visible')) {
// Slide away
$menu.animate({left: -($menu.outerWidth() + 10)}, function() {
$menu.hide();
});
}
else {
// Slide in
$menu.show().animate({left: 0});
}
});
});
You'll need to put position: relative on the menu element.
Note that I replaced your toggle with click, because that form of toggle was removed from jQuery.
If you want the menu to start out hidden, you can adjust the above. You want to know the element's width, basically, when putting it off-page.
This version doesn't care whether the menu is initially-visible or not: Live Copy | Live Source
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<div id="showmenu">Click Here</div>
<div class="menu" style="display: none; position: relative;"><ul><li>Button1</li><li>Button2</li><li>Button3</li></ul></div>
<script>
$(document).ready(function() {
var first = true;
// Hide menu once we know its width
$('#showmenu').click(function() {
var $menu = $('.menu');
if ($menu.is(':visible')) {
// Slide away
$menu.animate({left: -($menu.outerWidth() + 10)}, function() {
$menu.hide();
});
}
else {
// Slide in
$menu.show().css("left", -($menu.outerWidth() + 10)).animate({left: 0});
}
});
});
</script>
</body>
</html>
I would do something like this
DEMO in JsBin: http://jsbin.com/ofiqur/1/
Click Here
<div class="menu">
<ul>
<li>Button 1</li>
<li>Button 2</li>
<li>Button 3</li>
</ul>
</div>
and in jQuery as simple as
var min = "-100px", // remember to set in css the same value
max = "0px";
$(function() {
$("#showmenu").click(function() {
if($(".menu").css("marginLeft") == min) // is it left?
$(".menu").animate({ marginLeft: max }); // move right
else
$(".menu").animate({ marginLeft: min }); // move left
});
});
Try this:
<script type="text/javascript">
$.fn.toggleFuncs = function() {
var functions = Array.prototype.slice.call(arguments),
_this = this.click(function(){
var i = _this.data('func_count') || 0;
functions[i%functions.length]();
_this.data('func_count', i+1);
});
}
$('$showmenu').toggleFuncs(
function() {
$( ".menu" ).toggle( "drop" );
},
function() {
$( ".menu" ).toggle( "drop" );
}
);
</script>
First fuction is an alternative to JQuery deprecated toggle :) . Works good with JQuery 2.0.3 and JQuery UI 1.10.3
<script type="text/javascript" src="jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$(".click-header").click(function(){
$(this).next(".hidden-content").slideToggle("slow");
$(this).toggleClass("expanded-header");
});
});
</script>
.demo-container {
margin:0 auto;
width: 600px;
text-align:center;
}
.click-header {
padding: 5px 10px 5px 60px;
background: url(images/arrow-down.png) no-repeat 50% 50%;
}
.expanded-header {
padding: 5px 10px 5px 60px;
background: url(images/arrow-up.png) no-repeat 50% 50%;
}
.hidden-content {
display:none;
border: 1px solid #d7dbd8;
padding: 20px;
text-align: center;
}
<div class="demo-container">
<div class="click-header"> </div>
<div class="hidden-content">Lorem Ipsum.</div>
</div>
Use slideToggle(500) function with a duration in milliseconds for getting a better effect.
Sample Html
<body>
<div class="growth-step js--growth-step">
<div class="step-title">
<div class="num">2.</div>
<h3>How Can Aria Help Your Business</h3>
</div>
<div class="step-details ">
<p>At Aria solutions, we’ve taken the consultancy concept one step further by offering a full service
management organization with expertise. </p>
</div>
</div>
<div class="growth-step js--growth-step">
<div class="step-title">
<div class="num">3.</div>
<h3>How Can Aria Help Your Business</h3>
</div>
<div class="step-details">
<p>At Aria solutions, we’ve taken the consultancy concept one step further by offering a full service
management organization with expertise. </p>
</div>
</div>
</body>
In your js file, if you need child propagation for the animation then remove the second click event function and its codes.
$(document).ready(function(){
$(".js--growth-step").click(function(event){
$(this).children(".step-details").slideToggle(500);
return false;
});
//for stoping child to manipulate the animation
$(".js--growth-step .step-details").click(function(event) {
event.stopPropagation();
});
});

Issue with jQuery's slideDown()

Check this code: http://jsfiddle.net/ZXN4S/1/
HTML:
<div class="input">
<input type="text" size="50" id="test_input">
<input type="submit" value="send" id="test_submit">
</div>
<ul>
<li class="clear">
<div class="comment">
<div class="image">
<img src="http://www.chooseby.info/materiale/Alcantara-Black_granito_nero_naturale_lucido_3754.jpg">
</div>
<div class="info">
<div class="name">Name</div>
<div class="text">text</div>
<div class="timestamp">timestamp</div>
</div>
</div>
</li>
</ul>
jQuery:
$(document).ready(function() {
$("#test_submit").click(function() {
$.post('/echo/json/', function(data) {
last = $("ul li:first-child");
new_line = last.clone();
new_line.hide();
last.before(new_line);
new_line.slideDown('slow');
});
return false;
});
});
If you try to insert some text in the input field and click on the submit you can see the issue I'm talking about. When it slides down the height of slide is wrong and the effect is ugly. But if you remove the div info it works well. How can I fix?
Setting:
ul li .info {
float: left;
}
did it for me (tested in chrome)
This trick seems to solve the issue:
ul li .info {
float: right;
width: 485px; // fixed width to the div
}
The problem is simply the layout model. You can add overflow:hidden to give layout to an element in most browsers:
ul li .info {
overflow: hidden;
}
Will also solve it. You could fix your width optionally as well, but it's not required.
Bonus pedantic help that you didn't actually ask for:
You're using "return false" to prevent the default event. There's a function for that, which is more efficient in terms of how events bubble. Simply pass the event into the function (you can use any name you want, but I call it "event" for clarity) and then call preventDefault() on it:
$("#test_submit").click(function(event) {
event.preventDefault()
// ... the rest of your code ... //
});
After playing in JS Fiddle, this seems to have done the trick:
In your CSS, ul li .info { }
Add: height: 50px;

Categories

Resources