How to hide and retrieve a URL in CSS with Javascript - javascript

In CSS, I want to be able to specify a background image for a given selector without it actually being downloaded or rendered. I then want to be able to read the image URL with javascript, modify it in js, and then apply the modified URL to the selector for real so it will actually download and display. (I suppose that last part will have to be done with jQuery directly changing styles on each element, but that is not what this question is about.) This is part of some devious thing I'm trying to make really easy responsive images.
I have tried:
.sneaky {
background: url("youcantseemeyet.jpg");
background-image: url("blank.jpg");
}
But I can't find a way for javascript to know about the original background property.
Also tried:
.sneaky:after {
background: url("youcantseemeyet.jpg");
}
But I don't think javascript can see pseudo-elements.
Also tried:
.sneaky {
x-background: url("youcantseemeyet.jpg");
}
and:
.sneaky {
background: x-url("youcantseemeyet.jpg");
}
But I think javascript just tosses custom properties/values out the window.
How do CSS Polyfills work? Because they allow you to use CSS properties and values that would normally be invalid in a browser, so how does javascript access the CSS?
Another idea: I don't suppose there is a way to pre-empt the CSS with javascript, read the url() but block the file from downloading, is there?

I upvoted the question for your motivation to do this. Resposive Image resizing for Performance gain is a great way to reduce the bytes downloaded without affecting the quality of the page.
Here's one way of doing it: http://codepen.io/anon/pen/bNGgLZ
You can use html5 data attribute to store the url (so that the image is not downloaded initially) and then apply the image size based on the window size using javascript
<div class="sneaky" data-url="img_test.png">abcd</div>
<style>
.sneaky {
background: #000 url("transparent_placeholder.png");
color:#fff;
}
</style>
<script>
var el = document.querySelector(".sneaky");
alert(el.getAttribute("data-url"));
//Decide image size based on client window size and then assign backgroundImage property to download it from server
var size = "smaller";
el.backgroundImage = "url("+size+"_img_test.png)"
</script>

You can use the background position property to remove the image from rendering area and use window.getComputedStyle to retrieve the url
CSS
.sneaky {
background-image:url(youcantseemeyet.jpg);
background-position:-9999px -9999px;
}
Javascript
var url=window.getComputedStyle(document.querySelector('.sneaky'),null).backgroundImage
If you want to apply a second background images to .sneaky, better to include a sub div without padding/margin and apply second background to it

I figured out what to do. Kind of obvious now that I thought about it. Just hide the desired URL in a query string, like: url('/img/placeholder.gif?/path/to/real/image.jpg'). Ah, query strings, I love them.
UPDATE
A problem with using a query string is that every unique query string still results in a new HTTP request, even if it is ultimately returning the same resource. So, alternatively you can use a hash mark, like url('/img/placeholder.gif#/path/to/real/image.jpg'). When the image is requested, it will completely ignore the hash tag part, BUT you can still retrieve that information with javascript. It is just a bit tricky. Assuming you have no other URLs with hash tags in them (because why would you), you can simply retrieve a list of all selectors in all stylesheets which do use the hash tag part with the following script.
var selection = []
, sheets = document.styleSheets
, sheet, rule, i, j
for (i in sheets){
sheet = sheets[i]
for (j in sheet.cssRules) {
rule = sheet.cssRules[j]
if (/url\(.*#.*\)/.test(rule.cssText)) selection.push( rule.selectorText );
}
}

Related

Is there a way to change the colour of your website on the fly?

I'm trying to add branding to a web application based on a user defined setting or sub domain. This means changing the colours throughout the website when the user accesses the site using their sub domain or login.
Are there any JavaScript libraries out there or clever ways you can achieve this using Less/Sass.
I've already discovered the more obvious solution online of having multiple style sheets or having less files that import the main styles and override the main variables etc.
I'm hoping to find some sort of JavaScript library that can change colours on the fly or replace colours in a css file before render. Or maybe there are some cool css tricks out there that can help?
Any Ideas/solutions you may have will be a great help!
Edits
I'm not really looking to do a great deal of dom manipulation. i.e. changing classes on multiple elements etc. It's just really swapping colours or being able to manipulate style sheets before the pages are rendered.
I've got the sub domain / user setting side covered so its only the changing of styles etc that this question requires answers for.
I accept that questions similar to this have been asked before but mine is different. I'm trying to find any solutions other than just swapping a style sheet and I'm only really looking to change colours of the website.
This is a solution that I have come up with it works but it may not be the best way to do it.
I think the performance implications may out weigh the flexibility. I may be able to do something using cache to help.
It requires Less.js:
http://lesscss.org/usage/#using-less-in-the-browser
function changeTheme()
{
// get via api
var brand = {
'#primary' : "#000F46",
'#secondary' : "#CD3331",
'#text' : "#F2DA00"
};
less.modifyVars(brand);
}
try (js + css)
let subdomain = window.location.host.split('.')[0];
document.body.classList.add(subdomain);
console.log('subdomain:', subdomain);
/* COOMMON styles */
.myDiv {
padding: 20px;
background: #eee;
}
/* SUBDOMAINs styles */
body.stacksnippets .myDiv {
color:red;
}
body.othersubdomain .myDiv {
color:blue;
}
<div class="myDiv">Some value</div>
After question update
You can add different stylesheet depends on subdomain to html header as follows
let subdomain = window.location.host.split('.')[0];
let url = `https://example.com/pathtostyle/${subdomain}/yourstyle.css`
document.head.innerHTML +=
`'<link rel="stylesheet" type="text/css" href="${url}">'`;
console.log(url);

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.

Is there something like data-* attributes for css?

I want to pass a value that's set in a stylesheet so it can be read by javascript/jQuery? I thought of creating an invisible element and giving it a value, but then I would have to include that element in all the pages, which is pretty hacky. Just want to know if there's an alternative to that.
I have a js resize script for images that resizes based on area instead of height or width, so I can't feed it a maxwidth or maxheight, per se. if you give it 100, it makes the area of an image = 100^2. I suppose I could set the maxWidth of the element to twice the number I want, but I'm just wondering if there's a classier way to pull it off.
As far as I know, browsers throw away attributes they don't understand, so unfortunately you can't just inject your own data-*. I think you might have to do it via a hidden element, something like below, which uses the content attribute:
# styles.css
.data {
display: none;
content: "my data variable"
}
# index.html
<span class="data"></span>
# javascript
myData = $(".data").css('content')
Update
Playing around in Chrome, it looks like you can set the 'content' of an image and it won't show up. So you could do
# styles.css
img {
content: "100"
}
Not sure how well that works cross browser though, also looking at the w3c spec, it says that 'content' has to be used with :before or :after, so not sure if you'll run into validation issues there.
Why not just use javascript to query the actual element, and read its properties that way? Then you don't rely on the CSS at all.
$('someDiv').getWidth()

Rendered pIxel width data for each character in a browser's font

I have a table column that needs to be limited to a certain width - say 100 pixels. At times the text in that column is wider than this and contains no spaces. For example:
a_really_long_string_of_text_like_this_with_no_line_breaks_makes_the_table_unhappy
I would like to calculate the width of text server-side and add an ellipsis after the correct number of characters. The problem is that I don't have data about the rendered size of the text.
For example, assuming the browser was Firefox 3 and the font was 12px Arial. What would be the width of the letter "a", the width of the letter "b", etc.?
Do you have data showing the pixel width of each character? Or a program to generate it?
I think a clever one-time javascript script could do the trick. But I don't want to spend time re-inventing the wheel if someone else has already done this. I am surely not the first person to come up against this problem.
How about overflow: scroll?
Ext JS has a module to do just that
TextMetrics
Provides precise pixel measurements
for blocks of text so that you can
determine exactly how high and wide,
in pixels, a given block of text will
be.
I am sure that there are other libraries available out there that do it as well.
This would not only be impossible to do server-side, it would also not make sense. You don't what browser your client will be using, and you don't know what font settings on the client side will override whatever styling information you assign to a piece of HTML. You might think that you're using absolute positioning pixels in your style properties, but the client could simply be ignoring those or using some plugin to zoom everything because the client uses a high-dpi screen.
Using fixed widths is generally a bad idea.
Very very hard to do server-side. You can never know what fonts users have installed, and there are many things that affect the display of text.
Try this instead:
table-layout: fixed;
That'll make sure the table is never larger than the size you specified.
Here is my client-side solution that I came up with. It is pretty specific to my application but I am sharing it here in case someone else comes across the same problem.
It works a bit more quickly than I had expected. And it assumes the contents of the cells are text only - any HTML will formatting will be erased in the shortening process.
It requires jQuery.
function fixFatColumns() {
$('table#MyTable td').each(function() {
var defined_width = $(this).attr('width');
if (defined_width) {
var actual_width = $(this).width();
var contents = $(this).html();
if (contents.length) {
var working_div = $('#ATempDiv');
if (working_div.is('*')) {
working_div.html(contents);
} else {
$('body').append('<div id="ATempDiv" style="position:absolute;top:-100px;left:-500px;font-size:13px;font-family:Arial">'+contents+'</div>');
working_div = $('#ATempDiv');
}
if (working_div.width() > defined_width) {
contents = working_div.text();
working_div.text(contents);
while (working_div.width() + 8 > defined_width) {
// shorten the contents of the columns
var working_text = working_div.text();
if (working_text.length > 1) working_text = working_text.substr(0,working_text.length-1);
working_div.text(working_text);
}
$(this).html(working_text+'...')
}
working_div.empty();
}
}
});
}
This is essentially impossible to do on the server side. In addition to the problem of people having different fonts installed, you also have kerning (the letter "f" will take up a different amount of space depending on what is next to it) and font rendering options (is cleartype on? "large fonts"?).
There's nothing you can do server-side to calculate it. All you have to work with is the browser identification string, which may or may not tell you the user's operating system and browser accurately. You can also "ask" (via a font tag or CSS) for a certain font to be used to display the text but there's no guarantee that the user has that font installed. Beyond that the user could have a different DPI setting at the operating system level, or could have made the text bigger or smaller with the browser zoom function, or could be using their own stylesheet altogether.
You could put the text into an invisible span and read that spans width, but basicly this looks like someone trying to sabotage your site, and therefore I would recommend banning posts with words longer than a certain lenth, for example 30 characters without spaces (allowing links to be longer !-)
-- but the simple approach is to put a block-element inside the table-cell:
<td><div style="width:100px;overflow:hidden">a_really_long_string_of_text_like_this_with_no_line_breaks_makes_the_ta ... </div></td>
This will effectively stop the table-cluttering !o]
If you're ok with this not working for FireFox, why not just use CSS? Have the table with table-layout:fixed, have the column in question have overflow:hidden;text-overflow:ellipsis; white-space:nowrap.
http://www.css3.info/preview/text-overflow/
This is a new function of css3.
Some users have larger or smaller default font settings. You can't do this on the server. You can only measure it once the browser has rendered the page.
Since font size can be easily changed on the browser side, your server-side calculation is made invalid very easily.
A quick client side fix would be to style your cells with an overflow attribute:
td
{
overflow: scroll; /* or overflow: hidden; etc. */
}
A better alternative is to truncate your strings server side and provide a simple javascript tooltip that can display the longer version. An "expand" button may also help that could display the result in an overlay div.
What you want is the <wbr> tag. This is a special HTML tag that tells the browser that it is acceptable to break a word here if a wrap is necessary. I would not inject the into the text for persistent storage because then you are coupling your data with where/how you will display that data. However, it is perfectly acceptable to inject the tags server side in code that is view-centric (like with a JSP tag or possibly in the controller). That's how I would do it. Just use some regular expression to find words that are longer than X characters and inject this tag every X characters into such words.
Update: I was doing some looking around and it looks like wbr is not supported on all browsers. Most notably, IE8. I haven't tested this myself though. Perhaps you could use overflow:hidden as a backup or something like that.

How to hide img elements that do not have src attribute, until the attribute is added?

My JS code includes some images that are empty at the beginning
(without src attribute specified at all + display:none).
When added to sites with CSS1 compatibility I see broken image icon where the image should be even though the images are supposed not to be displayed (display:none).
Any idea how I can hide the broken image icons?
Notes:
I don't want to load empty images.
I tried width and height= 1px or 0px . didn't work.
specifying src="" also gives empty image icons.
Edit:
I found the solution:
add style="display:none" to the img definition (Not in CSS)
Have you tried wrapping the images inside a div and hiding the div instead?
My JS code includes some images that are empty at the beginning (without src attribute specified
That's not a valid state for an image. Best use a placeholder transparent image or leave the image out of the DOM until you can set a ‘real’ src attribute.
I see broken image icon where the image should be even though the images are supposed not to be displayed (display:none).
Doesn't happen for me, either ‘display: none’ or ‘visibility: hidden’ removes the visible image from the page. Example code demonstrating the problem, and which browser(s)?
The solution is quite simple:
add style="display:none" to the img definition (Not in CSS)
how about just having a placeholder div tag and replacing it with an image when the time comes to show the image? any decent ajax framework (e.g. jQuery) will make this easy to do so it works across all major browsers
in addition to display:none, maybe try setting visibility:hidden
If you are using a JavaScript library it may be worth applying a class to name to all of these images and letting the library handle it. Prototype example using a class name of myImages would be
var images = $$('.myImages');
if (image != null)
{
for (int i = 0; i < images.Length; i++)
{
images[i].hide;
}
}
You would still need to add the style attribute style="display: none;" to the images

Categories