How do URL fragment (the #stuff) interacts with CSS? - css

How does URL fragments interact with CSS? I have a page, say: http://example.boom/is_this_a_bug.html. The code for the page is shown in https://gist.github.com/3777018
When I load the page with the URL like that, the .tab-pane elements are not showed because they overflow their container, and it has an overflow: hidden property.
However, if I load the page by appending a valid fragment (#00) to the URL, then the .tab-pane gets visible, just as if the left:100% was not taken into account. Pressing the button just removes and resets left:100%, and then I get the overflowing tab-panes.
This happens in both Firefox 15.0.1 and Chromium 18.0.1025.168 (Developer Build 134367 Linux) Ubuntu 12.04.
Any ideas why this is happening? Is this a bug, or is documented elsewhere?
Best regards,
Manuel.

When you load a page with a fragment identifier in the URL, if that fragment identifier matches the ID of an element on the page the browser will scroll the page to bring that element into view.

An alternative can be use javascript applied styles.
(function hashStyle() {
if (window.location.hash == '#COLOR') {
var css = document.createElement('style'),
s = document.getElementsByTagName('script')[0],
styles = 'body { background-color: #b0c4de; }';
css.type = 'text/css';
if (css.styleSheet) {
css.styleSheet.cssText = styles;
} else {
css.appendChild(document.createTextNode(styles));
}
s.parentNode.insertBefore(css, s);
}
})();

Related

How to use CSS :hover on a toolbar button in Addon SDK

My addon was originally built in XUL and I am trying to redesign it using the addons SDK, and am having troubles getting icons to change/highlight when I hover the mouse over them.
I know how to apply a css stylesheet to an Addon SDK toolbar and its elements (and how to fetch the right #id to use). This allows me to change the background-color on a button, but I can't seem to make :hover work to change the button image.
It works if I assign a javascript listener for a mouseover event to the button, but if I have lots of buttons or menu items then this is way overkill compared to css.
One problem is that the button image is set on the sdk button element and it is an attribute of the button.
Now, I have tried using a transparent image for the button element's attribute and then using css to supply the image. Using XUL I would apply the image for the button or menu item with list-style-image.
So, my question is: How do I get :hover working in my css for an SDK toolbar button?
Here is the toolbarbutton-icon XUL binding:
<binding id="toolbarbutton-image"
extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
<content>
<xul:image class="toolbarbutton-icon" xbl:inherits="src=image"/>
</content>
</binding>
xbl:inherits="src=image" means that the image inherits its src attribute from the image attribute of the <toolbarbutton> thus list-style-image CSS is ignored.
The image property is set when you create the button with SDK APIs. While it is true that you cannot create an SDK button without an image, you can cheat the system either by removing the image attribute afterwards or by using a transparent image and then styling it with background-image just like in the normal web:
const { browserWindows: windows } = require("sdk/windows");
const { viewFor } = require("sdk/view/core");
const { attachTo } = require("sdk/content/mod");
const { Style } = require("sdk/stylesheet/style");
const { ActionButton } = require("sdk/ui/button/action");
var myButton = ActionButton({
id: "my-button",
label: "My Button",
icon: { "24": "./transparent24.png" },
});
let self = require("sdk/self");
let path = self.data.url(); // alternatively use chrome.manifest to register resource or chrome path
let widgetId = "action-button--toolkitrequire-my-button"; // get this from the Browser Toolbox
let css = `
#${widgetId} .toolbarbutton-icon {
background-image: url(${path}/icon24.png);
max-width: 24px;
}
#${widgetId}:hover .toolbarbutton-icon {
background-image: url(${path}/icon24-hover.png);
}`;
let style = Style({ source: css }); // or { uri: `${path}/style.css` }
for (let w of windows)
attachTo(style, viewFor(w));
Keep in mind that other styling may apply to the image so you better use Browser Toolbox to inspect the DOM. I am overriding max-width in this example.

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/

Iframe transparent background

My app has a modal dialog with an iframe inside it. I've written my jQuery code such that when the dialog opens, it sets the appropriate 'src' attribute of the iframe so the content loads up. However, during the delay between the dialog opening and the content loading, the iframe appears conspicuously as a white box. I'd prefer the iframe have a transparent background.
I've tried setting allowtransparency="yes" on the iframe. Any ideas? Thanks!
I've used this creating an IFrame through Javascript and it worked for me:
// IFrame points to the IFrame element, obviously
IFrame.src = 'about: blank';
IFrame.style.backgroundColor = "transparent";
IFrame.frameBorder = "0";
IFrame.allowTransparency="true";
Not sure if it makes any difference, but I set those properties before adding the IFrame to the DOM.
After adding it to the DOM, I set its src to the real URL.
<style type="text/css">
body {background:none transparent;
}
</style>
that might work (if you put in the iframe)
along with
<iframe src="stuff.htm" allowtransparency="true">
Set the background color of the source page to none and allow transparency in the iframe element.
Source page (for example, source.html):
<style type="text/css">
body
{
background:none transparent;
}
</style>
Page with iframe:
<iframe src="source.html" allowtransparency="true">Error, iFrame failed to load.</iframe>
Why not just load the frame off screen or hidden and then display it once it has finished loading. You could show a loading icon in its place to begin with to give the user immediate feedback that it's loading.
You need to make the iframe's body transparently. It works for me:
const iframe = document.createElement( 'iframe' );
iframe.onload = function() {
const doc = iframe.contentWindow.document,
head = doc.querySelector( 'head' ),
style = doc.createElement( 'style' );
style.setAttribute( 'type', 'text/css' );
style.innerHTML = 'body { background: transparent!important; }';
head.appendChild( style );
}

Moving ModalPopup Outside the IFrame. Possible?

I have an iframe inside my main page. There is a modalpopup inside the iframe page. So when the modalpopup is shown, the parent of the modalpopup is the iframe body and the main page parent body. Thus the overlay only covers the iframe and not the entire page.
I tried moving the modalpopup from the iframe to the parent windows body element (or any other element inside the parents body) using jQuery. I am getting an invalid argument error.
How do I show a modalpopup from an page inside iframe and it should cover the entire document, parent document as well?
Update:
Since few users are interested in achieving the same behavior .. here is the workaround
The best workaround that I would suggest would be to have the modalpopup in the main page .. and then invoke it from the iframe .. say something like this ..
/* function in the main(parent) page */
var _onMyModalPopupHide = null;
function pageLoad(){
// would be called by ScriptManager when page loads
// add the callback that will be called when the modalpopup is closed
$find('MyModalPopupBehaviorID').add_hidden(onMyModalPopupHide);
}
// will be invoked from the iframe to show the popup
function ShowMyModalPopup(callback) {
_onMyModalPopupHide = callback;
$find('MyModalPopupBehaviorID').show();
}
/* this function would be called when the modal popup is closed */
function onMyModalPopupHide(){
if (typeof(_onMyModalPopupHide) === "function") {
// fire the callback function
_onMyModalPopupHide.call(this);
}
}
/* functions in the page loaded in the iframe */
function ShowPopup(){
if(typeof(window.parent.ShowMyModalPopup) === "function") {
window.parent.ShowMyModalPopup.apply(this, [OnPopupClosed]);
}
}
// will be invoked from the parent page .. after the popup is closed
function OnPopupClosed(){
// do something after the modal popup is closed
}
Hope it helps
If you're using the iframe simply for scrollable content you might consider a styled div with overflow: auto or scroll, instead.
A set up such as this makes it easier to modify the appearance of the entire page since you're not working with multiple documents that each essentially have their own window space inside the page. You can bypass some of the cross-frame communication and it may be easier to keep the information in sync if you need to do that.
This may not be suitable for all situations and may require ajax (or modifying the dom with javascript) to change the div contents instead of just loading a different document in the iframe. Also, some older mobile browsers such as Android Froyo builds don't handle scrollable divs well.
You answered your own question in your update. The modal dialog needs to live on the parent page and invoked from the iframe. Your only other option is to use a scrolling div instead of an iframe.
It is not possible the way you are asking. Think of it this way: an iframe is a seperate window. You cannot (for the time being) move a div in one webpage into another.
I have done this by writing a small code for jQuery see below maybe this can help :
NOTE: Make sure you are doing on same domain
HTML:
<button type="button" id="popup">Show Popup</button>
<br />
<br />
<iframe src="your url" style="width: 100%; height:400px;"></iframe>
JS:
// Author : Adeel Rizvi
// It's just a attempt to get the desire element inside the iframe show outside from iframe as a model popup window.
// As i don't have the access inside the iframe for now, so I'll grab the desire element from parent window.
(function () {
$.fn.toPopup = function () {
return this.each(function () {
// Create dynamic div and set its properties
var popUpDiv = $("<div />", {
class: "com_popup",
width: "100%",
height: window.innerHeight
});
// append all the html into newly created div
$(this).appendTo(popUpDiv);
// check if we are in iframe or not
if ($('body', window.parent.document).length !== 0) {
// get iframe parent window body element
var parentBody = $('body', window.parent.document);
// set height according to parent window body
popUpDiv.css("height", parentBody.height());
// add newly created div into parent window body
popUpDiv.appendTo(parentBody);
} else {
// if not inside iframe then add to current window body
popUpDiv.appendTo($('body'));
}
});
}
})();
$(function(){
$("#popup").click(function () {
// find element inside the iframe
var bodyDiv = $('iframe').contents().find('YourSelector');
if (bodyDiv.length !== 0) {
// Show
$(bodyDiv).toPopup();
} else {
alert('Sorry!, no element found');
}
});
});
CSS:
.com_popup {
background-color: Blue;
left: 0;
position: absolute;
top: 0;
z-index: 999999;
}

Resources