20

I would like my chrome extension to be able to inject a 300px sidebar on the right side of any page when it is activated. I am looking for the best way to constrain the entire page to document.body.clientWidth - 300, thereby leaving the 300px on the right for my sidebar. The sidebar I currently inject is appended to document.body and has a style like so:

width:300px
position: fixed
top: 0px
right: 0px
height:500px

I need a way to prevent the existing page elements from bleeding over into my sidebar. I was hoping that there would be a way to trick the existing elements into thinking that they were rendering into a browser client 300px narrower than their actual window thereby leaving space for my sidebar but I haven't found any easy way to do so...

Dark Castle
  • 1,289
  • 2
  • 9
  • 20
  • In which site are you trying to inject your sidebar? See if you can minus 300px from the width of the container that exists on the page. – codef0rmer Apr 11 '12 at 06:16
  • This would have to work on ANY site. I can try and set a max-width on the body on a site but it may still have fixed position elements that will force it to bleed over. Elements may also override that max-width as well... – Dark Castle Apr 11 '12 at 06:26
  • Thats quite difficult to do. One more approach you can go with is to wrap the entire body DOM into a new div and then add margin-right:300px; to it but again fixed position and floated elements would create a problem. I would recommend to add a dock-able panel instead. – codef0rmer Apr 11 '12 at 06:49
  • Dockable panel would be ok but would still overlay content. Chrome has a panel window type for it's extensions but they are currently experimental. – Dark Castle Apr 11 '12 at 15:39

5 Answers5

14

I believe this is easier. First add padding to the body to make space for the sidebar. Then, create a div containing your sidebar. Position the div relative to the right and top of the page using CSS with fixed-positioning. Also set the height and width of the sidebar div.

Code (uses JQuery):

  var sidebar;
  $('body').css({
    'padding-right': '350px'
  });
  sidebar = $("<div id='sidebar'></div>");
  sidebar.css({
    'position': 'fixed',
    'right': '0px',
    'top': '0px',
    'z-index': 9999,
    'width': '290px',
    'height': '100%',
    'background-color': 'blue'  // Confirm it shows up
  });
  $('body').append(sidebar);
ssw
  • 143
  • 1
  • 4
12

Update

For anyone googling, overhauled this to reflect what I'm actually using in an app, use jQuery, have more safeguards, and be more respectful of current page css.

//height of top bar, or width in your case
var height = '30px';

//resolve html tag, which is more dominant than <body>
  var html;
  if (document.documentElement) {
    html = $(document.documentElement); //just drop $ wrapper if no jQuery
  } else if (document.getElementsByTagName('html') && document.getElementsByTagName('html')[0]) {
    html = $(document.getElementsByTagName('html')[0]);
  } else if ($('html').length > -1) {//drop this branch if no jQuery
    html = $('html');
  } else {
    alert('no html tag retrieved...!');
    throw 'no html tag retrieved son.';
  }

//position
if (html.css('position') === 'static') { //or //or getComputedStyle(html).position
  html.css('position', 'relative');//or use .style or setAttribute
}

//top (or right, left, or bottom) offset
var currentTop = html.css('top');//or getComputedStyle(html).top
if (currentTop === 'auto') {
  currentTop = 0;
} else {
  currentTop = parseFloat($('html').css('top')); //parseFloat removes any 'px' and returns a number type
}
html.css(
  'top',     //make sure we're -adding- to any existing values
  currentTop + parseFloat(height) + 'px'
);

You're almost done. You've styled the page html. You might have noticed css from the page affects your stuff to. You can resolve this by containing it within an iframe:

var iframeId = 'someSidebar';
if (document.getElementById(iframeId)) {
  alert('id:' + iframeId + 'taken please dont use this id!');
  throw 'id:' + iframeId + 'taken please dont use this id!';
}
html.append(
  '<iframe id="'+iframeId+'" scrolling="no" frameborder="0" allowtransparency="false" '+
    'style="position: fixed; width: 100%;border:none;z-index: 2147483647; top: 0px;'+
           'height: '+height+';right: 0px;left: 0px;">'+
  '</iframe>'
);
document.getElementById(iframeId).contentDocument.body.innerHTML =
  '<style type="text/css">\
    html, body {          \
      height: '+height+'; \
      width: 100%;        \
      z-index: 2147483647;\
    }                     \
  </style>                \
  <p>UNSTYLED HTML!</p>';

Yes, you have to append the iframe before setting the innerHTML

You should be able to copy/paste and edit this and be one your way!

Devin Rhode
  • 23,026
  • 8
  • 58
  • 72
  • This may be close thanks! I'll have to try it out later today. I briefly tried it this morning and had to adjust the document.documentElement.style.left as well as the max-width. Still not 100% equivalent to the user shrinking down their browser window to the expected size which would be optimal. – Dark Castle Apr 11 '12 at 16:14
  • Oh and by the way, yes I am using an iframe for the bar, you are correct, it does prevent css clashes. – Dark Castle Apr 11 '12 at 16:15
  • and the max z-index for anything is: 2147483647, use this – Devin Rhode Apr 11 '12 at 17:09
  • Many thanks for this...saved my sanity. I have this exact code working well - it bumps a page down x pixels and inserts my iFrame. But when I edit the code to place my iFrame on the right side the parent page moves left, but it doesn't resize. So my iFrame does NOT cover up content on the parent page (which is what I was trying to fix when I found this post). But 1/3 of the parent page is off the viewable page by 300px (width of my iFrame). Maybe vertical is better because a page will always scroll vertically? Any thoughts on refining for left/right displacement? Thanks again! – 11teenth Dec 01 '17 at 04:43
1

Thanks to Devin for the sample code. Unlike the other answers, this seemed to work. I actually used this code to write an extension aiming to solve this issue myself. However, I ran into difficulties when using it with certain Gmail tabs.

You can take a look at my hacked-together code for a working example of an iframe sidebar that isn't simply overlaid on the page. However, I haven't yet been able to overcome the aforementioned Gmail bug although this may not be an issue for you. I was simply bringing content in through the iframe src rather than inserting content with document.getElementById(iframeId).contentDocument.body.innerHTML.

Community
  • 1
  • 1
Turkeyphant
  • 222
  • 1
  • 3
  • 15
0

Well, you should just add z-index property to your css, set width to 300px and remove right.

BUT i hope you will change your mind :)

Dmitrii Sorin
  • 3,855
  • 4
  • 31
  • 40
  • I don't just want to overlay a sidebar on top of the page, I want it to force the existing contents to be constrained 300px from the right, like a sidebar such as the firefox bookmarks sidebar would behave. Popping a div on top of the page contents would be no problem. – Dark Castle Apr 11 '12 at 06:15
0

Chrome 114+ supports proper sidebars outside the document. The API is called sidePanel.

I believe you just need this manifest to make it appear in the native sidebar list:

{
  "name": "My side panel extension",
  "permissions": [
    "sidePanel"
  ],
  "side_panel": {
    "default_path": "sidepanel.html"
  }
}

You can also have it open when clicking on your extension action by adding this in your background worker:

chrome.sidePanel.setPanelBehavior({
  openPanelOnActionClick: true
});

and then this key to your manifest:

  "action": {
    "default_title": "Click to open panel"
  },
fregante
  • 29,050
  • 14
  • 119
  • 159