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()
Related
I have added a widget on my web site that shows on the lower-right corner of the screen, but I'd rather it appeared on the bottom-left side. The google tag is a script like this
<script src="https://leadbooster-chat.pipedrive.com/assets/loader.js" async></script>
And after loading the script generates an iframe with appropriate css positioning
HTML
<iframe role="complementary" scrolling="no" id="LeadboosterContainer" class="proactiveChat" style="height:100px !important"></iframe>
CSS
#media (min-width: 576px)
<style>
html body #LeadboosterContainer {
bottom: 28px !important;
right: 28px !important;
}
It turns out the widget is not configurable via their interface to appear on the left hand screen (I'll send them a suggestion), but I have discovered that simply changing the right: 28px !important; to a left is enough to produce a quite acceptable behavior.
I'm aware that the developers may change this property in the future, and that the solution I'm thinking of would be a bit dirty, but is it possible to accurately target the CSS generated AFTER the widget is loaded via the script, and change the right to a left ? As you can see, the challenges here
The script is loading the HTML asynchronously
There is is a media query (and actually there are several rules that would need changing)
there is a !important flag which makes it harder to override this CSS rule in a brand new stylesheet
this is an iframe on another website... so we cannot do anything we want since security policies apply inside the iframe, and we only have the control on the iframe element itself for positioning
How can I do this ? I need to trigger an event after an async script has started, and then find a way to target media queries.
An example of what I'm thinking of adding to my google tag
// TODO : find a way to fire this code after the script has loaded / implement runAfterChatBotHasLoaded
runAfterChatBotHasLoaded( function() {
var pipedriveBot = document.getElementById("LeadboosterContainer");
// TODO : find a way to target each media query
position = pipedriveBot.getAttribute('right');
pipedriveBot.setAttribute('left', position)
pipedriveBot.removeProperty('right'));
});
I have also tried
Adding rules via https://davidwalsh.name/add-rules-stylesheets (I run into a Uncaught DOMException: Failed to execute 'insertRule' on 'CSSStyleSheet': The index provided (1) is larger than the maximum index (0).
Various ideas from Find all CSS rules that apply to an element
If the widget is in the iframe then you require either:
GTM in the iframe, not just the parent window
The post message api to securely call functions between the iframe and parent window (the parent window being where GTM is loading)
If the css you are targeting is in the iframe then you need to treat it as a different website that doesn't have your GTM container loaded on it.
If you're trying to move the iframe to the bottom left then this is working for me in a jsfiddle:
var pipedriveBot = document.getElementById("LeadboosterContainer");
// remove the styling
pipedriveBot.style.setProperty('bottom', '0', 'important');
// Add your own
pipedriveBot.style.position = "fixed";
pipedriveBot.style.left = "0px";
See also this article on removing css properties that are set with !important: How can you remove an important CSS property?
Let me know if I have understood correctly. If you need to wait until the DOM contains LeadboosterContainer then you can set a function to check the DOM periodically and then fire a function.
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.
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 );
}
}
edit:
The problem seems to be that the font size isnt explicitly set and is set by the css class only. so style.fontSize always returns an empty string
if there another way to return the font size?
var allMainFrameElems = parent.main.document.getElementsByTagName('*');
for (i=0; i < allMainFrameElems.length; i++){
if(allMainFrameElems[i].style.fontSize != null){
alert(llMainFrameElems[i].style.fontSize);
}
}
If the fontSize style in not explicitly set on an element (e.g. <p style="font-size:12pt;">...</p>), you won't be able to get it from anywhere. Font-sizes are most often set in your CSS classes, which are not reachable from your element's properties, and the elements do not have any font-size related properties.
In order to even come close to doing this you will need to do some tricks and will not be able to definatively determine font size. Basically you will have to manipulate the page a great deal on every element (not good) just to determine this.
See this fiddle page, especially the pixelPerEm function I tossed together very quickly. http://jsfiddle.net/MarkSchultheiss/vc8Zy/
It is not very clean at the moment and IF I get time I might try to make it better but it might give you something to start with even if it is NOT very pretty.
EDIT: basic explanation is to utilize the em css, inject an element with a known setting, calculate the pixel offset on the injection and then remove the injected element. None of that is pretty and all of it is error/bug prone or has potential for issues.
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.