Scrollposition as a variable in css? - css

I'm working on a webpage with very complex non default scroll behaviour. Stuff is suppose to move over the screen based on how much you scroll and stuff like that. I know I can use javascript to add classes on different positions, something like this:
wrap.on("scroll", function(e) {
if (this.scrollTop > 147) {
wrap.addClass("fix-search");
} else {
wrap.removeClass("fix-search");
}
});
But now I need the actual scrollposition as a value in css. I would like to do something like this, this should cause a object to fly up over the screen twice as fast as you are scrolling.
.floatingObject {
position: absolute;
bottom: calc(var(--scrollPosition)*2);
}
Is something like this possible? Can you maybe store the value in the DOM and retrieve it as a css-variable/property etc?

Yes,
In your scrollListener just add something like the following:
document.documentElement.style.setProperty('--scrollPosition', this.scrollTop);
In your css :root {--scrollPosition:0}
Mind that this has no support in IE so you'll need a fallback everywhere you want to use the variable.

Related

if image width > 400 = image width = 100% css

I'd like to check if an image width has more than 400px I'd like this image to get full div width. if image is less than 400px just print it in its normal size.
any ideas how to do this?
<div id="volta">
<img src="/img/volta.jpg">
</div>
#volta{
width:500px;
}
As far as I know, this does not exist in CSS. What you should do instead is use classes.
Define some CSS class that applies the styles you want:
.long_width {
background: blue;
}
Then you would use Javascript to check the width of the image. You don't need jQuery to do this you can do it in vanilla Javascript (unless you already have jQuery imported and need it for other things). Maybe something like this:
let elm = document.querySelector('[src="/img/volta.jpg]"');
let width = window.getComputedStyle(elm).getPropertyValue('width');
And then you would use Javascript to add and remove styles accordingly:
if (width > 400) {
elm.classList.add("long_width");
}
else {
elm.classList.remove("long_width");
}
The specific answer to your question depends on what your intentions are. But to keep your code simple, you should use Javascript to handle the logic and not depend on CSS selectors for things this complicated. Instead, create a CSS class that contains the styles you need, and then use Javascript to apply it based on the size of the user uploaded image.
Additionally, if the user uploads the image, you should load it into memory and check its attributes in memory rather than by depending on a DOM element. Something like:
let img = new Image();
img.src = "{data URL of img}"
You will need javascript / jQuery to work. Something like this:
$('img').each(function(){
if($(this).width() > 400){
$(this).css('width', '100%');
}
});
Here is also working jquery example.
Apply an id to the image, and with jquery check its width
If it is greather than 400px modify his width or add a class that does the same.
Example
$(document).ready(function(){
if($("#image").width() > 400){
$("#image").css("width", "100%");
}
else{
$("#image").css("width", "10px");
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id = "image" src = "https://pm1.narvii.com/6919/98f453834b5d87a6c92118da9c24fe98e1784f6ar1-637-358v2_hq.jpg"/>
You can do it like FlokiTheFisherman (with %), or you can use "wv" instead of "%".
I recommend using vw.
img[width='400'] {
width: 100%;
}

page transitions in meteor - not quite working?

so in the back of the 'discover meteor' book they explain how to do page transitions. i've got it working, however it causes problems with the loading of javascript functions and variables on other pages that its animating into. it seems they're not ready or simply don't exist at the time the page is routed.
Template.layout.onRendered(function() {
this.find('.pos-rel')._uihooks = {
insertElement: function(node, next) {
$(node).hide().insertBefore(next)
.delay(200)
.velocity("transition.slideUpIn", 1000)
},
removeElement: function(node) {
$(node).velocity({
opacity: 0,
},
{
duration: 100,
complete: function() {
$(this).remove();
}
});
}
}
});
if i remove the above code then all my javascript variables and functions work correctly. does anyone have another working solution to page transitions using velocity.js ? i did find this one but its a year old and i couldn't get it to work at all, it just makes the content where '{> yield}' is go blank :(
Just a note for asking questions on stack overflow: "causes problems with the loading of javascript functions and variables" is pretty vague. Its best to give more specifics.
But anyways, you said here that you're using isotope to render items in a grid. I'm assuming you're calling $elements.isotope() within a Template[name].onRendered callback.
This is probably the issue because its trying to compute and rearrange into a grid the elements while they're hidden. Using display: none actually removed the elements, thus isotope can't compute the sizes, etc. for the layout. Try this:
insertElement: function(node, next) {
$(node).css("opacity", 0).insertBefore(next)
.delay(200)
.velocity("transition.slideUpIn", {duration:1000, display:null})
},
opacity: 0 should do what you're looking for. It will make them transparent without removing them from the transition.slideUpIn should animate opacity so you're good there.
Also, velocity transitions mess with the display property. Setting display: null in the animation options prevents it from setting the display to block or whatever it wants to do. This may or may not be necessary, but I pretty much always use it.
You could use:
onAfterAction
onBeforeAction
. The solution should be something like this:
animateContentOut = function() {
$('#content').css('display', 'none');
this.next();
}
fadeContentIn = function() {
$('#content').velocity('transition.fadeIn',1000);
}
Router.onBeforeAction(animateContentOut)
Router.onAfterAction(fadeContentIn)

Styling Google Translate widget for mobile websites

My website - www.forex-central.net - has the Google Translate drop-down widget on the top right of every page.
Only problem is it's a bit too wide for my website (5 cm), I would need a 4 cm version (which I've seen on other sites so I know this is possible)...but I have no idea how to tweak the code.
The code Google supplies for the widget I use is:
<script type="text/javascript">function googleTranslateElementInit() { new google.translate.TranslateElement({ pageLanguage: 'en', gaTrack: true, layout: google.translate.TranslateElement.InlineLayout.SIMPLE }, 'google_translate_element');}</script><script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
Any help would be greatly appreciated! I'm a bit of a novice and have searched for hours on this, not getting anywhere :-/
Something like this will get you started:
.goog-te-menu-frame {
max-width:100% !important; //or whatever width you want
}
However, you would also need to do something like:
.goog-te-menu2 { //the element that contains the table of options
max-width: 100% !important;
overflow: scroll !important;
box-sizing:border-box !important; //fixes a padding issue
height:auto !important; //gets rid of vertical scroll caused by box-sizing
}
But that second part can't actually be done because the translate interface is included in your page as an iframe. Fortunately, it doesn't have its own domain, so we can access it via Javascript like this:
$('.goog-te-menu-frame').contents().find('.goog-te-menu2').css(
{
'max-width':'100%',
'overflow':'scroll',
'box-sizing':'border-box',
'height':'auto'
}
)
But that won't work until the element actually exists (it's being loaded asynchronously) so we have to wrap that in something that I got here. Put it all together, you get this:
function changeGoogleStyles() {
if($('.goog-te-menu-frame').contents().find('.goog-te-menu2').length) {
$('.goog-te-menu-frame').contents().find('.goog-te-menu2').css(
{
'max-width':'100%',
'overflow':'scroll',
'box-sizing':'border-box',
'height':'auto'
}
)
} else {
setTimeout(changeGoogleStyles, 50);
}
}
changeGoogleStyles();
Whew.
You can use that same strategy to apply other styles to the translate box or perhaps alter the table styles to have it flow vertically instead of scroll horizontally offscreen, whatever. See this answer.
EDIT:
Even this doesn't work, because Google re-applies the styles every time you click the dropdown. In this case, we try and change height and box-sizing, but Google reapplies over those, while overflow and max-width stick. What we need is to put our styles somewhere they won't get overriden and add !importants [cringes]. Inline styles will do the trick (I also replaced our selector with a variable for succinctness and what is likely a negligible performance boost):
function changeGoogleStyles() {
if(($goog = $('.goog-te-menu-frame').contents().find('body')).length) {
var stylesHtml = '<style>'+
'.goog-te-menu2 {'+
'max-width:100% !important;'+
'overflow:scroll !important;'+
'box-sizing:border-box !important;'+
'height:auto !important;'+
'}'+
'</style>';
$goog.prepend(stylesHtml);
} else {
setTimeout(changeGoogleStyles, 50);
}
}
changeGoogleStyles();
The Google Translate widget creates an iframe with content from another domain (several files from Google servers). We would have to manipulate the content inside the iframe, but this so-called cross-site scripting did not work for me. I found another solution. I downloaded two of the many files which the widget uses, so I could edit them.
Bear in mind that Google can change its API anytime. The hack will have to be adapted then.
Prerequisite:
I assume that the widget is working on your website. You just want to fit it on smaller screens. My initial code looks like:
<div id="google_translate_element"></div>
<script type="text/javascript">
function googleTranslateElementInit()
{
new google.translate.TranslateElement({pageLanguage:'de', layout: google.translate.TranslateElement.InlineLayout.SIMPLE}, 'google_translate_element');
}
</script>
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
If your initial code looks different, you might have to adapt your solution accordingly.
Special tools used:
Chrome DevTools (adapt for other browsers)
Procedure:
In Google Chrome, right-click on your page containing the Google Translate widget.
Click Inspect. A window or side pane will apper with lots of HTML info.
In the top line, select the Sources tab.
Browse the sources tree to
/top/translate.google.com/translate_a/element.js?cb=googleTranslateElementInit
Click the file in the tree. The file content will be shown.
Under the code window of element.js, there is a little button with two curly brackets { }. Click this. It will sort the code for better readability. We will need this readability in the next steps.
Right-click inside the element.js code > Save as…. Save the file inside the files hierarchy of your website, in my case:
/framework/google-translate-widget/element.js
Point your <script> tag to the local element.js.
<!--<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>-->
<script type="text/javascript" src="../framework/google-translate-widget/element.js?cb=googleTranslateElementInit"></script>
From now on, your website should load element.js from its local directory. Now is a good moment to check if your Google Translate widget still works. Also check in Chrome DevTools where the browser has taken the file from (Google server or local directory). It should sit in the sources tree under
/top/[your domain or IP]/framework/google-translate-widget/element.js?cb=googleTranslateElementInit
We need another file from Google servers. Browse the sources tree to
/top/translate.googleapis.com/translate_static/css/translateelement.css
Download this file after clicking the curly brackets { }. I saved it in my website files directory as
/framework/google-translate-widget/translateelement.css
In your website files directory, open element.js and change line 66:
//c._ps = b + '/translate_static/css/translateelement.css';
c._ps = '/framework/google-translate-widget/translateelement.css';
From now on, your website will also load translateelement.css from its local directory. Check this now.
Open your local translateeleent.css and append the following styles at the end:
/* Make all languages visible on small screens. */
.goog-te-menu2 {
width: 300px!important;
height: 300px!important;
overflow: auto!important;
}
.goog-te-menu2 table,
.goog-te-menu2 table tbody,
.goog-te-menu2 table tbody tr {
width: 100%!important;
height: 100%!important;
}
.goog-te-menu2 table tbody tr td {
width: 100%!important;
display: block!important;
}
.goog-te-menu2 table tbody tr td .goog-te-menu2-colpad {
visibility: none!important;
}
I borrowed the code from another answer: Google translate widget mobile overflow
The geometry might work now, but we broke another thing. The widget text showing “Select Language”, “Sélectionner une langue”, or whatever it says in you language, is locked to that language now. Since you want your other-language readers to understand the offer, the widget should adapt to their language as it used to work before our hack. Also, the listed languages’ names are affected. The reason for this bug can be found in the file element.js, which was silently tailored to our browser’s language setting. Look in element.js on lines 51 and 69
c._cl = 'fr';
_loadJs(b + '/translate_static/js/element/main_fr.js');
In my case, it was set to French (fr).
Correcting line 51 is as simple as
c._cl = 'auto'; //'fr';
Line 61 is trickier, because there is no 'auto' value available. There is a file main.js (without the _fr ending) available on Google servers, which provides English as a fallback, but we prefer the user’s language. Have a look in the file
/top/translate.googleapis.com/translate_a/l?client=…
It contains two objects. sl and tl meaning the source languages and target languages supported for translation. We have to check if the user’s browser is set to one of the target languages. There is a JavaScript constant navigator.language for this.
Edit element.js at line 69:
// determine browser language to display Google Translate widget in that language
var nl = navigator.language;
var tl = ["af","sq","am","ar","hy","az","eu","bn","my","bs","bg","ceb","ny",
"zh-TW","zh-CN","da","de","en","eo","et","tl","fi","fr","fy","gl",
"ka","el","gu","ht","ha","haw","iw","hi","hmn","ig","id","ga","is",
"it","ja","jw","yi","kn","kk","ca","km","rw","ky","ko","co","hr",
"ku","lo","la","lv","lt","lb","mg","ml","ms","mt","mi","mr","mk",
"mn","ne","nl","no","or","ps","fa","pl","pt","pa","ro","ru","sm",
"gd","sv","sr","st","sn","sd","si","sk","sl","so","es","sw","su",
"tg","ta","tt","te","th","cs","tr","tk","ug","uk","hu","ur","uz",
"vi","cy","be","xh","yo","zu"];
var gl = "";
if( tl.includes( nl )) gl = '_'+nl;
else
{
nl = nl.substring(0, 3);
if( tl.includes( nl)) gl = '_'+nl;
else
{
nl = nl.substring(0, 2);
if( tl.includes( nl)) gl = '_'+nl;
else gl = '';
}
}
_loadJs(b + '/translate_static/js/element/main'+gl+'.js');
//_loadJs(b + '/translate_static/js/element/main_fr.js');
… should do the trick.
Try using this in your CSS
.pac-container, .pac-item { width: 100px !important;}
where you can alter the with of the dropdown by altering 'the 100px' value.
This should work. Let me know if it doesn't and I'll have another look.

How can I prevent CSS from affecting certain element?

I am writing a GreaseMonkey script that sometimes creates a modal dialog – something like
<div id="dialog">
Foo
</div>
. But what can I do if the site has something like
#dialog {
display: none !important;
}
? Or maybe the owner of some site is paranoid and has something like
div {
display: none !important;
}
div.trusted {
display: block !important;
}
because he doesn't want people like me adding untrusted content to his page. How can I prevent those styles from hiding my dialog?
My script runs on all pages, so I can't adapt my code to each case.
Is there a way to sandbox my dialog?
Actually a very interessting problem, here is another approach:
adding an iframe and modifying it creates a seperate css space for you (your sandbox)
look at this jsfiddle example: http://jsfiddle.net/ZpC3R/2/
var ele = document.createElement("iframe");
ele.id = "dialog";
ele.src = 'javascript:false;';
ele.style.height = "100px";
ele.style.width = "300px";
ele.style.setProperty("display", "block", "important");
document.getElementById("dialog").onload = function() {
var d = document.getElementById("dialog").contentWindow.document;
// ... do your stuff within the iframe
};
this seems to work without problem in firefox.
now you only have to make sure that the iframe is untouched, you can do this they way i described in my 1. answer
just create the div like this:
var ele = document.createElement("div");
ele.style.setProperty("display", "block", "important");
that should overwrite all other styles afaik.
look here, it seems to work: http://jsfiddle.net/ZpC3R/

CSS if/else statement for counting list items

I need an if/else statement for my CSS which can count list items. Would this be possible?
Basically I want to say, if there are less than 10 list items, the UL container should be 200px wide, and it there are more than 10 list items, it should be 400px wide. Something like that.
Can it be done?
I would appreciate a working demo on jsFiddle, both so I can see working code, and for anyone who looks here in the future so they can see a working example and how to do it :)
CSS only does styles, but not dynamically (unless with assistance of JS). you can use the following JS snippet for the task. just to make sure, load this at the very last, just before the </body>
<script type="text/javascript">
(function resize() {
//get all lists with selected name
var lists = document.getElementsByClassName('myList');
//loop through all gathered lists
for (i = 0; i < lists.length; i++) {
//shorthand elements for easy use
var list = lists[i];
var items = list.getElementsByTagName('li');
//append class names
list.className = (items.length < 10) ? 'myList less' : 'myList more';
}
}())​
</script>
.less{
width:200px;
}
.more{
width:400px;
}​
CSS has no if else statements. You can do this easily with jQuery. Another option would be to use LESS or SCSS.
Short answer: no. CSS offers no conditional support.
Long answer: you need to use javascript or a server side language to either add a class when there are more than 10 items (or elements) in the list, or in the case of javascript, directly manipulate the style after it's loaded.
That doesn't sound possible for CSS. There are no logical if/else statements in the CSS spec. Your next best bet would probably be javascript. You could achieve this with jQuery with the following code:
if($('ul#target-list li').length < 10) {
$('ul#target-list').css('width', 200);
}
else {
$('ul#target-list').css('width', 400);
}
Pure CSS3 Solution
If you only want to support CSS3, then this does what you need:
li {
width: 200px;
}
li:nth-last-child(n+11),
li:nth-last-child(n+11) ~ li {
width: 400px;
}
But you will need to make the ul either display: inline-block or float it so that the width is controlled by the li elements themselves. This may require you to wrap the ul (display: inline-block) in a div so that it still is a block element in the flow of the page if you need it so.

Resources