Shopify liquid code, how to use screensize - javascript

I want to display radio boxes and dropdowns for selecting a variant on desktop and only dropdowns on mobile.
At the moment it displays the desktop variant on both. And I would have to differ within the liquid code which creates the dropdowns/radio boxes between the screen size. So that it can create the right elements.
But as liquid can not differ between it. I need a workaround for it.
I can also not put a around it and differ with js, because the liquid code in it does not work anymore.
Does someone know a workaround for that?
Thank you!

The lightest and optimized solution would be to use a CSS class with media queries instead of JS. If your stylesheet do not already have this kind of utility classes, you may create one.
So, in your HTML/Liquid code, you might write something like:
<div class="checkbox-container hide-tablet">
Your checkbox code
</div>
And in your CSS stylesheet:
#media screen and (max-width:912px) {
display:none;
}
HTH

If anyone has the same problem as well, I found some sort of workaround.
I create both needed elements (dropdown and radio boxes) for this one option and just remove one of them depending on the screen size:
if (screen.width < 912) {
var child = document.getElementById("packaging-selection-desktop");
child.parentNode.removeChild(child);
}
else {
var child = document.getElementById("packaging-selection-mobile");
child.parentNode.removeChild(child);
}

Related

Can I use javascript to place one element on different places, one for mobile and one for desktop?

I am adding an element in the dom using javascript. I have added an using insertBefore() to place it where I want it on the mobile view. But in desktop it is supposed to be placed on a different space on the website. How can i solve this?
Just using CSS is not an option due to already existing elements that i cant't move.
var priceWrapper = document.querySelector('.price-info-wrap')
var mainContainer = document.querySelector('.price-info')
var addUrgency = document.getElementById('urgency')
priceWrapper.insertBefore(addUrgency, mainContainer)
The code provided is how I have placed "addUrgency" witch is the div I need to put elsewhere on desktop.
You can do it, but it's a bad idea.
Lay out your elements starting with smallest screen width you need, then work outwards from there using CSS Media queries to adjust the layout at specific screen widths as and when you need to.
In this case, if you can't do it any other way you could have both elements where you like them and then show/hide depending on the viewport width. Something like:
#media (min-width:800px) {
//your non-mobile styles and classes go here
.desktop-element{
display: inline-block;
}
.mobile-element{
display:none;
}
}
You could use navigator.userAgent and determine if the browser is a mobile browser. There is also an question with really good answeres on doing that on StackOverflow: Detecting a mobile browser
Another option is to check the viewport-size with javascript. Which can be a better solution in the case you have css-rules in place that are responsive to the viewport-size , like: #media (width):
let width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
After that it is a simple if-else to decide where to place your element.
You can use the onresize event. But, I have to note, that having two identical elements (perhaps using clone() to copy #addUrgency) in the DOM on their right places and display/not display them using CSS media queries instead of using Javascript to re-lay elements every time the viewport is resized is a better solution. However, to answer your question here is the most straightforward approach using your code. It also worth to note, that resize event can fire pretty fast, so you probably will want to throttle the function relay (answers are on StackOverflow).
function relay(){
var addUrgency = document.getElementById('urgency');
if(`mobile view`){ //here goes a condition to determine what view you have.
var priceWrapper = document.querySelector('.price-info-wrap');
var mainContainer = document.querySelector('.price-info');
priceWrapper.insertBefore(addUrgency, mainContainer);
}else{
// Insert where you want it on desktop view
}
}
window.onload = function() {
relay();
document.body.addEventListener("resize", relay);
};
You could do this using JavaScript but I wouldn't recommend this approach as I believe this is achievable in most cases with plain HTML and CSS. One method would be using display: grid and placing the elements in the desired rows/columns on mobile (If you are of course utilizing a mobile-first approach) and then redistributing them on larger screens with media queries. Additionally, you could of course make use of position: absolute whenever this strategy does not completely do the job.
Here is a great article, in case you are not completely familiar with display: grid.

How to disable Evernote web view "max-width" with JavaScript?

Evernote places a max-width limit on web view content, and I have identified its location in Chrome developer tool(F12). Evidence: Unticking the checkbox beside "max-width" will stretch the table to full window width.
My question is, how can I remove that css statement with JavaScript code?
I have tried this:
document.getElementById("container").style.removeProperty("max-width")
but in vain.
The above web page can be reached at http://www.evernote.com/l/ABXYD6q6bM9MyaAfRs78hQnq6VMINfVJODg/
Given that this statement isn't set as inline style, you won't be able to remove it.
However, you could change its value and set it to none by adding an inline style declaration, which will override the current value.
Demo:
var elem = document.getElementById('container');
elem.style.maxWidth = 'none';
Not sure how webview works, but could you try using javascript to add a new class to it that added a max-width of 100%?
document.getElementById("container").classList.add('no-max-width');
then in the styles.css put
.no-max-width {
max-width: 100%; }
If that's not possible, then try
document.getElementById("container").style.maxWidth('100%');
Though I sometimes have trouble with .styles so not sure if that is exactly right, plus I've read it's better to add classes rather than play with css styles in JS, but also not sure how accurate that is.

jQuery Add & Remove Class Div Width

How can i add/remove class according as div width ? I tried some codes but I have no idea about jquery codes. I'd like add div class according as antoher div width. Just i need add class like that. If container is smaller than 600px "add class" to content div else "remove class" from content div. These are my codes;
<div class="container">
<div class="content"></div>
</div>
$(window).resizeboxes(function() {
if ($(".container").width < 600){
$( ".content" ).addClass( ".content_600" );
}
});
else{
removeClass('.content_600')
}
$(window).trigger('resizeboxes');
This works, though the code is changed slightly. There were some problems with the syntax also, so I've corrected those (for instance the else statement was slightly misplaced). Here is a working example:
https://jsfiddle.net/vt0nbx36/3/
Here is the code:
var resizeboxes = function() {
if ($(".container").width() < 600)
{
$(".content").addClass("content_600");
}
else
{
$(".content").removeClass("content_600")
}
};
resizeboxes();
$(window).resize(function(){
resizeboxes();
});
For this need exactly, you have jQuery's .toggleClass() function. It takes the class name as a first parameter, and optional second boolean parameter that states wether the class name should be added or removed. You can find the documentation here
$(".content").toggleClass("content_600", ($(".container").width() < 600));
Even tho your question is a JS related question, CSS as a matter of fact can handle this like no other beast can (mostly)!
CSS allows you to use media-queries to resize your content based on the width of the viewport.
The upside of this is that the browser will handle this for you within the rendering engine rather than having JS between your change and the rendering engine.
The major downside is that you can't define the width of element A based on element B but are unfortunately locked to using the viewport as an indicator.
Before I explain why you'd want to use CSS I'd like to point out why you don't want to use JS for this if possible.
The jQuery.resize eventhandler fires inconsistently across browsers and it fires alot of times usually.
This causes your scrolling to clog up and make your webpage feel laggy.
If there's anything your users will dislike it's the fact that scrolling is controlled by something they don't even know of which is slowing you down.
As for a CSS solution, a media query looks like this:
.my-selector {
width: 900px;
}
#media all and (max-width: 600px) {
.my-selector {
width: 600px;
...
}
}
You wrap your code in a sort-of conditional that allows you to be very flexible with manipulating elements on the page.
What happens in the above piece of code is that when the parser reads the CSS it sees the first selector not in a media query so it applies width: 900px; then it sees a media query and sees the other rule for my-selector however it will only apply that rule when the screen is at that width we defined in the #media ... rule. When you resize CSS handles things differently behind the scenes so it's much faster than JS in that case.
I'm not sure if it actually applies to your situation but if your container is sized by the viewport rather than parent elements this should be possible and I thought it'd be nice atleast to show you a good way of playing with element dimensions.
Also, you can use #media to for instance make a webpage print friendly by changing the all to print for example and setting the background-color: transparent for an element - saves ink ^.^ which is an additional extra on top of the general awesomeness of media queries.
Hope it helps, good luck if you wish to make your webpage 5 times faster ;)

Remove CSS property completely

I have a button, which when clicked loads an additional CSS file, that overrides a great part of the basic CSS files. (this is for accessibility purposes if you wonder)
Let's say I have a background and background-color properties used in multiple selectors for input[type='text']. I want to reset/delete those. I DON'T want to set a new value for those background properties, I want to remove them, so that the browser will render everyting as it would by default.
The reason for this is because in high contrast mode with black background color to the body in Firefox, any background set to input or button will override it with a value equal to the text color which will make the value of the input or the button unreadable. But that's another story...
EDIT: Since everybody so far is telling me to set some new property to those, I'm writing it in bold big letters - I DON'T NEED TO SET NEW PROPERTY FOR background. :) The reason behind that if that property is present Firefox defaults it to black if the background set in the high contrast mode is black as well. To test this, go to Preferences -> Content -> Colors and check Allow pages to choose their own colors, instead of my selections above. Here's how my options look.
You can remove the original stylesheet. Just assign it an id and use jQuery.remove(...).
The alternate solution is to alter the first stylesheet to use some kind of namespace+, for example:
/* these are the rules that you want to be removed */
.stylesheet1 { }
.stylesheet1 h1 { }
.stylesheet1 p { }
.stylesheet1 a { }
.stylesheet1 input { }
/* these rules can co-exist with the next stylesheet */
nav { }
article { }
aside { }
section { }
Inside your HTML add the stylesheet1 class to body. When you load the other CSS file (presumably via JavaScript) then you remove this class. All namespaced rules will become ineffective.
* CSS preprocessors e.g. SASS and LESS make it easier for you to manage these rules.
Do a css reset/normalize at the beginning in your first css file. Then at the beginning of the second one do it again.
You can leave out the first reset, but this will give you consistent results.
It sounds like the best solution for you is to have two different CSS classes targeting a single input, and toggle back and forth between the two. There are several ways to do this:
CSS:
input[type="text"].a {...}
input[type="text"].b {...}
Here we have two different classes, a and b. When defining the input initially, set class="a". We'll then swap that with b when the button is clicked. Again, there are several ways of doing this:
jQuery:
$('.a').click(function(){
$(this).removeClass('a').addClass('b');
});
Plain JS
var button = document.querySelector('.a');
button.addEventListener('click', function(){
button.classList.remove('a');
button.classList.add('b');
});
This is the generally preferred method for achieving this kind of behaviour. It adheres strictly to standards, in that it separates logic, markup, and presentation into their respective pieces.
Note: The plain JS method listed above uses some pretty modern native JS code. Take a look at You Might Not Need jQuery to find suggestions for making this functionality cross-browser.
Instead of adding or removing properties to elements, I think the better way to do it is to put these extra properties in a CSS class and then add or remove this extra class to the elements as needed. And if you need override, then use !important. Now it's just about add/removing classes.
Here's an example in jQuery
.MyControl{background: blue;}
.MyControlAccessibility{background: red !important;}
$(SomeControl).click(function () { $(this).addClass('MyControlAccessibility'); }
$(SomeControl).click(function () { $(this).removeClass('MyControlAccessibility'); }
Using a global class on the body is good as mentioned.
Another way could be to put your light and dark "theme"-specific styles into separate stylesheets from the common CSS and then disable the one you do not want. This will avoid conflicts and needing to use !important, and you can keep things clean without having to hack away at various bits of jquery.css().
For example
base.css
a { text-decoration:none; }
dark.css
body { background-color:#000; }
a {color:#fff; font-size:1.2em;}
light.css
a {font-size:1.5em;}
Note that light.css has no properties for background-color etc. so when they switch from dark to light, the defaults will be used again.
To do the switch, you can do something along these lines:
for (var i = 0; i < document.styleSheets.length; i++) {
var ss = document.styleSheets[i];
// some browsers store in url, others in href
if((ss.href || ss.url || '').indexOf('dark.css') > -1) {
ss.disabled = true;
}
}
By disabling instead of removing the current one, it should be easier to switch between the two.

"Disabling" an HTML table with Javascript

I've seen this done in a lot of sites recently, but can't seem to track one down. Essentially I want to "disable" an entire panel (that's in the form on an HTML table) when a button is clicked.
By disable I mean I don't want the form elements within the table to be usable and I want the table to sort of fade out.
I've been able to accomplish this by putting a "veil" over the table with an absolutely positioned div that has a white background with a low opacity (so you can see the table behind it, but can't click anything because the div is in front of it). This also adds the faded effect that I want. However, when I set the height of the veil to 100% it only goes to the size of my screen (not including the scrolling), so if a user scrolls up or down, they see the edge of the veil and that's not pretty.
I'm assuming this is typically done in a different fashion. Does anyone have some suggestions as a better way to accomplish this?
You could try javascript like:
function disable(table_id)
{
var inputs=document.getElementById(table_id).getElementsByTagName('input');
for(var i=0; i<inputs.length; ++i)
inputs[i].disabled=true;
}
Try the below with Jquery
$("#freez").click(function(){
$('#tbl1').find('input, textarea, button, select').attr('disabled','disabled');
});
$("#unfreez").click(function(){
$('#tbl1').find('input, textarea, button, select').removeAttr("disabled");
});
Disabling the inner elements of an HTML table can also be done using pointer-events CSS style as shown below:
table[disabled], table[disabled] input { pointer-events: none }
At any desired point in our JavaScript code, we can add disabled attribute to the parent table which will bring the CSS styling into effect:
let gameTable = document.getElementById('gameBoard');
gameTable.setAttribute('disabled', true);
Another way to do it would be using the opacity property.
function disablePanel(id) {
var panel = document.getElementById(id);
var inputs = panel.querySelectorAll('input, button'); //anything else can go in here
for (var i=0; i<inputs.length; i++) {
inputs[i].disabled = true;
}
panel.style.opacity = 0.3; //or any other value
}
Can't you just find out the height of the area in pixels with JavaScript? And then set the veil's height to that number?
I don't have the exact code in my head but offsetHeight might do the trick
Somebody please correct me if I am wrong, but I have seen Javascript and some derivate Javascript libraries that have a lot of options for accomplishing for what you would like to do. I have used the jQuery library to do some similar effects.
One thing to think about is what exactly you are trying to disable. Essentially tables are not interactive so disabling a table would not accomplish much. If it is the form elements within the table you want to disable. You can accomplish this using JavaScript.
Along with using JavaScript for disabling the form elements, you can also use it to change properties of the non interactive elements.
An example of this would be using JavaScript to change the color of the font and borders and other non interactive elements in the table to give the "look" of being disabled. Of course you still need to use JavaScript to disable the form elements.

Categories