I have a website built on SASS. There're certain variables I want to change while switching between light and dark themes, but all variables get compiled and converted to its original value. Hence, I don't know how to change SASS variables while changing themes.
Assuming I have following variables in style.scss:
$mainColor: #eaeaea;
$secondaryColor: #fff;
$mainText: black;
$secondaryText: #2a3a47;
$borderColor: #c1c1c1;
$themeDotBorder: #24292e;
$previewBg: rgba(251, 249, 243, 0.8);
$previewShadow: #f9ead6;
$buttonColor: #0a0a0a;
How do I change these variables while switching themes. I can create two separate css files but that would be redundant code. Can you help me?
Depending on your build process and requirements for older browsers, for example ie11.
Themes becomes easier with css custom properties (css variables). The basic idea is that you have your variables, and on theme change you change the color of the variables.
In my very very basic example the following things happen and why.
On root level set your variables for your default theme.
Have a class with the describing the theme, in my example it is .dark-theme
Set a class on the body when dark-theme is active with js, or postback depending on your backend and wanted approach. In my example I do it with js.
What happens here is that in .dark-theme we change the variables to the dark theme colors. That is the basics of it and will get you far.
Just a note, the approach on saving the theme all depends on what kind of site you have SPA, Wordpress, .NET ect. I seen mentions about saving it in the database and user, that kinda don't hold up if you don't have user signing. One approach is to save it in the browsers local storage and read it when you load the page.
const themeSwitcherButton = document.querySelector('.js-theme-switcher')
themeSwitcherButton.addEventListener('click', function() {
const body = document.querySelector('body')
if (body.classList.contains('dark-theme')) {
body.classList.remove('dark-theme')
} else {
body.classList.add('dark-theme')
}
})
:root {
--primary-color: deepskyblue;
}
body.dark-theme {
--primary-color: deeppink;
}
.block {
margin-bottom: 3rem;
padding: 2rem;
background-color: var(--primary-color);
}
<body>
<p class="block">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima quos odio atque excepturi, aut voluptate. Similique autem, eos rem cum tenetur perspiciatis voluptatibus reprehenderit cumque, inventore, nam laudantium fugiat molestias eveniet sit commodi deleniti. Ipsa eum animi, excepturi tempore placeat.
</p>
<button class="js-theme-switcher">Theme switcher</button>
</body>
use css variables instead of sass one
--mainColor: #eaeaea;
and
color: var(--mainColor);
to use it
edit:
to change dynamically css variables
var bodyStyles = document.body.style;
bodyStyles.setProperty('--mainColor', 'white');
if variables was declared on body element
I'm using Polymer web components, and I'm finding that the default height of the core-pages element is 0. I want it to depend on the height of its child elements, ideally the height of the selected child.
Here's an example page that demonstrates the issue (live jsbin):
<!DOCTYPE html>
<html>
<head>
<script src="https://www.polymer-project.org/components/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="https://www.polymer-project.org/components/core-pages/core-pages.html">
</head>
<body>
<h1>Before <core-pages> element</h1>
<core-pages selected="0" block>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.</div>
</core-pages>
<h1>After <core-pages> element</h1>
<script>
// Uncomment this kludge to fix the layout.
/* window.addEventListener('polymer-ready', function() {
var selected = document.querySelector('core-selected');
var height = window.getComputedStyle(selected).height;
document.querySelector('core-pages').setAttribute('style', 'height:' + height);
}); */
</script>
</body>
</html>
On my desktop Chrome 39, the trailing header overlaps the core-pages content (instead of appearing below it) because the core-pages element is given a height of 0 (which I believe is because the core-pages implementation uses absolute positioning on the child elements, but I could be wrong).
This can be "fixed" by giving the core-pages element an explicit height (such as with the commented javascript in the example), but this is undesirable and really should be triggered on reflow. It's ugly and doesn't align with Polymer's declarative emphasis.
Is there any elegant way to fit core-pages to its content so it lays out in an intuitive manner? I'm hoping there is some magical CSS or Polymer setting that will fix this.
I came to the following workaround.
Say, we have a core-pages nesting my custom component mudasobwa-custom:
<core-pages selected="0" block>
<mudasobwa-custom>CONTENT</mudasobwa-custom>
</code-pages>
Let’s define a PolymerExpression like:
PolymerExpressions.prototype.elementSize = function(el) {
var result = { w: 0, h: 0 };
for (ch in el) {
result.w += el[ch].offsetWidth;
result.h += el[ch].offsetHeight;
}
return result;
};
Then we need to define a computed property on the core-pages descendant components (one might surround the content with “wrapper” component whether core-pages are nesting pure HTML elements, which is not my case; I have mudasobwa-custom component nested.)
<!-- don’t forget to publish ⇓⇓⇓⇓⇓ -->
<polymer-element name="mudasobwa-custom" attributes="sizes ......
.......
Polymer({
.......
needupdate: boolean,
computed: {
sizes: 'elementSize($, needupdate)'
}
.......
Once the needupdate changes it’s value, the expression is to be recalculated (use it for explicit triggering.) The only think left is to bind core-pages width/height to this computed property:
<!-- use auto binding ⇓⇓⇓⇓⇓⇓⇓ -->
<core-pages ... style="height:{{ sizes.h }}px;">
<mudasobwa-custom sizes="{{ sizes }}">
This approach might look overengineered, but it requires the expression to be written only once and then you immediately yield an access to all the real widths/heights.
Live: http://plnkr.co/edit/U98IzTxUVUuEUuPbxNgF?p=preview
Hope it might help somebody.
In the <core-pages> demo page ( https://www.polymer-project.org/components/core-pages/demo.html ) they use also an explicit height to solve the problem, so I guess that it's the "official" way for now...
I'll try some CSS tricks latter to see if I can find a more elegant solution...
If not needed the absolute positioning of the children, you can position them relative inside the core pages:
In your example:
core-pages > div {
position: relative !important;
}
http://codepen.io/anon/pen/vEZjWd
i have long text like that :-
"5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experience5 Simple Steps to Improve Patient Experienc
"
But i need only 2 line to show on page and a more button to check complete text.
Is this posible with angular.js ?
if yes What would you suggest me ?
Yes, this is totally possible with AngularJS -- but most of the solution is actually CSS.
You'll be able to do this mostly through CSS. First, HTML/CSS doesn't really have a concept for how many lines a bunch of text is taking up. You can get the behavior you want by setting the height of a container element and the line-height of your text on the CSS line-height. For your default state, set the height based on two times your line height and set the overflow to hidden. Then you just need have your button conditionally apply a class that expands the height of the container and sets the overflow to visible:
<style>
.container {
font-size: 16px;
line-height: 16px;
height: 32px;
overflow: hidden;
}
.show {
overflow: visible;
height: auto;
}
<div class="container" ng-class="{show: show}">
[your text]
</div>
<button ng-click="show = true">Show text</button>
You can get fancy and make the button also hide the text again (as a toggle).
ng-text-truncate
https://github.com/lorenooliveira/ng-text-truncate
Demo 1
https://rawgit.com/lorenooliveira/ng-text-truncate/master/demo1.html
Example
<p ng-text-truncate="longTextVariable"
ng-tt-chars-threshold="40"></p>
angular-read-more
https://github.com/ismarslomic/angular-read-more
Demo
http://codepen.io/ismarslomic/pen/yYMvrz
<div hm-read-more
hm-text="{{ text }}"
hm-limit="100"
hm-more-text="read more"
hm-less-text="read less"
hm-dots-class="dots"
hm-link-class="links">
</div>
If you'd prefer to have a div that truncates itself based on pixel height instead of character count, you can try this. This allows you to put nested HTML in your expandable section.
angular.module('app', [])
.controller('TestController', function($scope) {
$scope.loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
})
.directive('showMore', function() {
return {
restrict: 'A',
transclude: true,
template: [
'<div class="show-more-container"><ng-transclude></ng-transclude></div>',
'More',
'Less',
].join(''),
link: function(scope, element, attrs, controller) {
var maxHeight = 45;
var initialized = null;
var containerDom = element.children()[0];
var $showMore = angular.element(element.children()[1]);
var $showLess = angular.element(element.children()[2]);
scope.$watch(function () {
// Watch for any change in the innerHTML. The container may start off empty or small,
// and then grow as data is added.
return containerDom.innerHTML;
}, function () {
if (null !== initialized) {
// This collapse has already been initialized.
return;
}
if (containerDom.clientHeight <= maxHeight) {
// Don't initialize collapse unless the content container is too tall.
return;
}
$showMore.on('click', function () {
element.removeClass('show-more-collapsed');
element.addClass('show-more-expanded');
containerDom.style.height = null;
});
$showLess.on('click', function () {
element.removeClass('show-more-expanded');
element.addClass('show-more-collapsed');
containerDom.style.height = maxHeight + 'px';
});
initialized = true;
$showLess.triggerHandler('click');
});
},
};
});
.show-more-container {
overflow: hidden;
}
.show-more-collapse, .show-more-expand {
text-align: center;
display: none;
}
.show-more-expanded > .show-more-collapse {
display: inherit;
}
.show-more-collapsed > .show-more-expand {
display: inherit;
}
<script src="https://code.angularjs.org/1.5.8/angular.js"></script>
<div ng-app="app" ng-controller="TestController">
<div show-more>
All sorts of <strong>stuff</strong> can go in here.
{{ loremIpsum }}
<div>Even more divs</div>.
</div>
<div show-more>
This <strong>won't</strong> truncate.
</div>
</div>
I think there is an easier way.
Just replace {{text}} with {{text | limitTo: 150}}, and then create below simple read more link.
I want to disable the double-tap zoom functionality on specified elements in the browser (on touch devices), without disabling all the zoom functionality.
For example: One element can be tapped multiple times for something to happen. This works fine on desktop browsers (as expected), but on touch device browsers, it will zoom in.
Note (as of 2020-08-04): this solution does not appear to work in iOS Safari v12+. I will update this answer and delete this note once I find a clear solution that covers iOS Safari.
CSS-only solution
Add touch-action: manipulation to any element on which you want to disable double tap zoom, like with the following disable-dbl-tap-zoom class:
.disable-dbl-tap-zoom {
touch-action: manipulation;
}
<button>plain button</button>
<button class="disable-dbl-tap-zoom">button with disabled double-tap zoom</button>
<p>A <b>plain</b> paragraph. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.</p>
<p class="disable-dbl-tap-zoom">A paragraph <b>with disabled double-tap zoom</b>. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.</p>
From the touch-action docs (emphasis mine):
manipulation
Enable panning and pinch zoom gestures, but disable additional non-standard gestures such as double-tap to zoom.
This value works on Android and on iOS.
<head>
<title>Site</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
etc...
</head>
I've used that very recently and it works fine on iPad. Haven't tested on Android or other devices (because the website will be displayed on iPad only).
CSS to disable double-tap zoom globally (on any element):
* {
touch-action: manipulation;
}
manipulation
Enable panning and pinch zoom gestures, but disable additional non-standard gestures such as double-tap to zoom.
Thanks Ross, my answer extends his: https://stackoverflow.com/a/53236027/9986657
I know this may be old, but I found a solution that worked perfectly for me. No need for crazy meta tags and stopping content zooming.
I'm not 100% sure how cross-device it is, but it worked exactly how I wanted to.
$('.no-zoom').bind('touchend', function(e) {
e.preventDefault();
// Add your code here.
$(this).click();
// This line still calls the standard click event, in case the user needs to interact with the element that is being clicked on, but still avoids zooming in cases of double clicking.
})
This will simply disable the normal tapping function, and then call a standard click event again. This prevents the mobile device from zooming, but otherwise functions as normal.
EDIT: This has now been time-tested and running in a couple live apps. Seems to be 100% cross-browser and platform. The above code should work as a copy-paste solution for most cases, unless you want custom behavior before the click event.
I just wanted to answer my question properly as some people do not read the comments below an answer. So here it is:
(function($) {
$.fn.nodoubletapzoom = function() {
$(this).bind('touchstart', function preventZoom(e) {
var t2 = e.timeStamp
, t1 = $(this).data('lastTouch') || t2
, dt = t2 - t1
, fingers = e.originalEvent.touches.length;
$(this).data('lastTouch', t2);
if (!dt || dt > 500 || fingers > 1) return; // not double-tap
e.preventDefault(); // double tap - prevent the zoom
// also synthesize click events we just swallowed up
$(this).trigger('click').trigger('click');
});
};
})(jQuery);
I did not write this, i just modified it. I found the iOS-only version here: https://gist.github.com/2047491 (thanks Kablam)
If you need a version that works without jQuery, I modified Wouter Konecny's answer (which was also created by modifying this gist by Johan Sundström) to use vanilla JavaScript.
function preventZoom(e) {
var t2 = e.timeStamp;
var t1 = e.currentTarget.dataset.lastTouch || t2;
var dt = t2 - t1;
var fingers = e.touches.length;
e.currentTarget.dataset.lastTouch = t2;
if (!dt || dt > 500 || fingers > 1) return; // not double-tap
e.preventDefault();
e.target.click();
}
Then add an event handler on touchstart that calls this function:
myButton.addEventListener('touchstart', preventZoom);
You should set the css property touch-action to none as described in this other answer https://stackoverflow.com/a/42288386/1128216
.disable-doubletap-to-zoom {
touch-action: none;
}
* {
-ms-touch-action: manipulation;
touch-action: manipulation;
}
Disable double tap to zoom on touch screens. Internet explorer included.
Simple prevent the default behavior of click, dblclick or touchend events will disable the zoom functionality.
If you have already a callback on one of this events just call a event.preventDefault().
If you only want to prevent double click zoom across all devices, try setting the dblclick event listener of the button to preventDefault(). This worked for me!
edit: typo in 'dblclick'
const button = document.querySelector('#button');
button.addEventListener('dblclick', function(el) {
el.preventDefault();
});
<button id="button"> No double click zoom here</button>
If there is anyone like me who is experiencing this issue using Vue.js,
simply adding .prevent will do the trick: #click.prevent="someAction"
Disable double tap zoom on mobile (2023 IOS Safari solution):
I found that using the meta tag method was not a viable solution for mobile safari browsers. Here is the solution that worked for me.
working solution:
.selector {
touch-action: manipulation;
}
by simply adding a touch-action of manipulation all buttons with the following rule applied will not zoom on consecutive clicks of the button.
example website: calculator app
This will prevent double tap zoom on elements in 'body' this can be changed to any other selector
$('body').bind('touchstart', function preventZoom(e){
var t2 = e.timeStamp;
var t1 = $(this).data('lastTouch') || t2;
var dt = t2 - t1;
var fingers = e.originalEvent.touches.length;
$(this).data('lastTouch', t2);
if (!dt || dt > 500 || fingers > 1){
return; // not double-tap
}
e.preventDefault(); // double tap - prevent the zoom
// also synthesize click events we just swallowed up
$(e.target).trigger('click');
});
But this also prevented my click event from triggering when clicked multiple times so i had to bind a another event to trigger the events on multiple clicks
$('.selector').bind('touchstart click', preventZoom(e) {
e.stopPropagation(); //stops propagation
if(e.type == "touchstart") {
// Handle touchstart event.
} else if(e.type == "click") {
// Handle click event.
}
});
On touchstart i added the code to prevent the zoom and trigger a click.
$('.selector').bind('touchstart, click', function preventZoom(e){
e.stopPropagation(); //stops propagation
if(e.type == "touchstart") {
// Handle touchstart event.
var t2 = e.timeStamp;
var t1 = $(this).data('lastTouch') || t2;
var dt = t2 - t1;
var fingers = e.originalEvent.touches.length;
$(this).data('lastTouch', t2);
if (!dt || dt > 500 || fingers > 1){
return; // not double-tap
}
e.preventDefault(); // double tap - prevent the zoom
// also synthesize click events we just swallowed up
$(e.target).trigger('click');
} else if(e.type == "click") {
// Handle click event.
"Put your events for click and touchstart here"
}
});
Here's a variation that currently, as of 2022, does the trick on most device versions; Android / iOS.
Note that for example iOS 14+ zooms in on any text input fields that has a font-size of less than 1rem 16px, which also quite senior pros seem to have missed.
A vanilla javascript example - that can be improved further - for example with logic to allow normal behavior scenarios too - so for your experimentation.
document.getElementById('selectorid').addEventListener('touchend' || 'dblclick', event => {
event.preventDefault();
event.stopImmediatePropagation();
}, {
passive: false
});
Here's a more covering example for testing purposes to see if it achieves wished results. This one affects all the elements on the page inherited in the DOM.
/* For testing purposes, overrides events that may trigger a "zoom"; note that this may cause other unexpected behavior */
window.addEventListener('touchmove' || 'touchdowm' || 'touchend' || 'mousedown' || 'dblclick', event => {
event.preventDefault();
event.stopImmediatePropagation();
}, {
passive: false
});
Here's some simple CSS, for overriding test purposes - try it out on the page and you may expect a remedy clue if form fields are what's bugging. Although the minimum size of 16px is actually quite wishfully intentional for accesibillity concerns. Note that the "!important" flag isn't considered good practice to manifest in a production deploy.
/* CSS to test prevention of zoom when interacting with input fields */
input[type=text] {
font-size: 1rem !important;
}
most of the coding above doesn't work unfortunately
these simple lines will do it
document.addEventListener('dblclick', function(event) {
event.preventDefault();
}, { passive: false });
I assume that I do have a <div> input container area with text, sliders and buttons in it, and want to inhibit accidental double-taps in that <div>.
The following does not inhibit zooming on the input area, and it does not relate to double-tap and zooming outside my <div> area. There are variations depending on the browser app.
I just tried it.
(1) For Safari on iOS, and Chrome on Android, and is the preferred method. Works except for Internet app on Samsung, where it disables double-taps not on the full <div>, but at least on elements that handle taps. It returns return false, with exception on text and range inputs.
$('selector of <div> input area').on('touchend',disabledoubletap);
function disabledoubletap(ev) {
var preventok=$(ev.target).is('input[type=text],input[type=range]');
if(preventok==false) return false;
}
(2) Optionally for built-in Internet app on Android (5.1, Samsung), inhibits double-taps on the <div>, but inhibits zooming on the <div>:
$('selector of <div> input area').on('touchstart touchend',disabledoubletap);
(3) For Chrome on Android 5.1, disables double-tap at all, does not inhibit zooming, and does nothing about double-tap in the other browsers.
The double-tap-inhibiting of the <meta name="viewport" ...> is irritating, because <meta name="viewport" ...> seems good practice.
<meta name="viewport" content="width=device-width, initial-scale=1,
maximum-scale=5, user-scalable=yes">
Using CSS touch-events: none
Completly takes out all the touch events. Just leaving this here in case someone also has this problems, took me 2 hours to find this solution and it's only one line of css.
https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action
Here we go
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
I am using jQuery and AJAX on my website. My AJAX respond is a text representing the continuance of an article. I've read that there's a STEP function in jQuery's animate but I don't know how to use that to append text character by character to a DIV element.
Please Help me.
Thanks in advance. :D
Try this.
var someajaxtext = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras interdum sem sit amet magna convallis sed ullamcorper mi commodo.';
$('button').click(function () {
var dv = $('#mydiv');
dv.text("");
jQuery({
count: 0
}).animate({
count: someajaxtext.length
}, {
duration: 1500,
step: function () {
dv.text(someajaxtext.substring(0, Math.round(this.count)));
}
});
});
Demo here: http://jsfiddle.net/naveen/evVMw/
P.S: Change the duration as you wish.