3

In my webpage I am trying to get a custom scroll bar. It is working fine.

Now I have a theme button which allows user to choose either a black theme or a white theme. For this I wrote two css files, one carbon.css and another quartz.css

When a user clicks on one of the themes, I am updating the css file with the below function.

I am able to see all changes correctly except the scroll bar. Until I hover my mouse over the scroll bar, that css change is not happening.

To be more clear, suppose i am in black theme. I am seeing black scroll bar. Now when I click the white theme, I am seeing all my background, text changing properly to white theme. But the scroll bar still remains in black theme. Once I move my mouse on to scroll bar it is updating the scroll bar to white theme.

How can I solve this problem?

Thanks!

Hey Anubav: here is the code I am working after including your changes:

trail.html

  <html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  <script   type="text/javascript" src="./jquery-1.7.1.min.js"></script>
  <link href="./carbon.css" rel="stylesheet" type="text/css" id="extCSSFile"/>
  <script type="text/javascript">
  $(document).ready(function() {
  function changeAndPaint(that){

        var filename = $(that).attr('data-href');

    $('#extCSSFile').attr('href',filename);
        var newfile = $('#extCSSFile');

        $('#extCSSFile').remove();
        $(that).css('display','none').height(); //<--this is the trick to repaint
        $(that).css('display','inherit');       


        var elem = $('<link href="" rel="stylesheet" type="text/css" id="extCSSFile"/>');
        $(elem).attr('href',filename);  
        $('head').append(elem);

    }

        $('#carbonTheme,#quartzTheme').on('click', function(){
                changeAndPaint($(this));
            }); 
            });
            </script>
   </head>
  <body>
 <ul id="nav">
    <li id="carbonTheme" data-href="./carbon.css">carbon Theme </li>
    <li id="quartzTheme" data-href="./quartz.css">Quartz Theme </li>
 </ul>      
  <div> 
           <p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p><p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p><p>There are no results</p>
            <p>There are no results</p>

            <p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p>
           <p></p>
           <p></p><p></p><p></p><p></p><p></p>
           <p></p><p></p><p></p><p></p><p></p>
           <p></p><p></p><p></p><p></p><p></p>
           <p></p><p></p><p></p><p></p><p></p>
           <p></p>


            </div>
            </body>
            </html>

carbon.css

body {
    font-family: Arial, Helvetica, sans-serif;      
    font-size:8.5pt;  
    width:inherit;
    min-width:100px;
    max-width:250px;
    margin:10px;
    background-color:#191919;
    color:white;    
}

 ul{height:1000px;}

 #carbonTheme, #quartzTheme{ 
 text-decoration:underline;
 color:blue;
  }
  ::-webkit-scrollbar {
    width: 12px;
 }

::-webkit-scrollbar-track {
 background-color:#aaa;
}

::-webkit-scrollbar-thumb {

  background-color:black;
}

quartz.css

body {
    font-family: Arial, Helvetica, sans-serif;      
    font-size:8.5pt;  
    width:inherit;
    min-width:100px;
    max-width:250px;
    margin:10px;

 }
  ul{height:1000px;}

  #carbonTheme, #quartzTheme{ 
  text-decoration:underline;
  color:blue;
 }
 ::-webkit-scrollbar {
 width: 12px;
 }

 ::-webkit-scrollbar-track {
  background-color:#333;
 }

  ::-webkit-scrollbar-thumb {

   background-color:white;
 }
javaMan
  • 6,352
  • 20
  • 67
  • 94
  • I am guessing that scroll bar is related to window not with webpage. so it is not loading until some event is happening to window. Am I right. If so how can i solve this issue. – javaMan Sep 07 '12 at 20:05
  • 1
    `rel="./css/black.css">`?!! I don't think you know what `rel` means. – Quentin Sep 10 '12 at 13:04
  • 1
    use data-href instead of rel. –  Sep 10 '12 at 20:08
  • 1
    yes working just fine. There is one issue though, when I inspect this code using built in inspector in chrome, some times, just some times it doesn't work; may be because of `./` . Other than that yes, this is code is working just fine. Also, I don't have stable chrome or safari. Does this thing work on older chrome or safari? –  Sep 11 '12 at 20:07
  • yaa... i also see it working some times and not working sometimes. not sure why it is happening – javaMan Sep 11 '12 at 20:15
  • tried on older versions. working sometimes and not working some times. – javaMan Sep 11 '12 at 20:27

6 Answers6

3

To force the browser to repaint the complete DOM just do $("#body").offset().Top; ( body is the ID given to body tag to speed up the selector )

A simple approach to your task can be just add a attribute disabled="disabled" to your link element

Include LINK in HEAD section as :

<link href="./carbon.css" rel="stylesheet" type="text/css" id="carbonCSS" />
<link href="./quartz.css" rel="stylesheet" type="text/css" id="quartzCSS" disabled="disabled" />

Include Script Below the link as :

 <script   type="text/javascript" src="./jquery-1.7.1.min.js"></script>
<script type="text/javascript">
      $(document).ready(function() {
            $('#nav li').on('click', function(){
                    objLink = document.getElementById($(this).attr("data-href"))
                    $("#carbonCSS , #quartzCSS").attr("disabled","disabled");
                    $("#body").offset().Top;  // Force Repaint
                    objLink.removeAttribute("disabled");
                }); 
        });
 </script> 

Complete html page may look like :

<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

  <link href="./carbon.css" rel="stylesheet" type="text/css" id="carbonCSS" />
  <link href="./quartz.css" rel="stylesheet" type="text/css" id="quartzCSS" disabled="disabled" />

   <script   type="text/javascript" src="./jquery-1.7.1.min.js"></script>
    <script type="text/javascript">
      $(document).ready(function() {
            $('#nav li').on('click', function(){
                    objLink = document.getElementById($(this).attr("data-href"))
                    $("#carbonCSS , #quartzCSS").attr("disabled","disabled");
                    $("#body").offset().Top;
                    objLink.removeAttribute("disabled");
                }); 
        });
    </script>
   </head>
<body id="body">
 <ul id="nav">
    <li id="carbonTheme" data-href="carbonCSS">carbon Theme </li>
    <li id="quartzTheme" data-href="quartzCSS">Quartz Theme </li>
 </ul>      
  <div> 
           <p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p><p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p><p>There are no results</p>
            <p>There are no results</p>

            <p>There are no results</p>
            <p>There are no results</p>
            <p>There are no results</p>
           <p></p>
           <p></p><p></p><p></p><p></p><p></p>
           <p></p><p></p><p></p><p></p><p></p>
           <p></p><p></p><p></p><p></p><p></p>
           <p></p><p></p><p></p><p></p><p></p>
           <p></p>


            </div>
</body>
</html>
GajendraSinghParihar
  • 9,051
  • 11
  • 36
  • 64
2

There are a few weird things about this solution. As @Quentin pointed out, you shouldn't use the rel attribute simply for a variable storage area. You may want to either use the css path in the href attribute (since you're returning false anyway) or set a class or id for each link at "black" or "white".

On top of that when you say just $('link') you're automatically just changing the href of your first link element on the page. I would use an id attr for your theme link element, so you always know you're changing that one (whether you add other links in before that).

Your method also will then add an http request every time you click to change themes.

I think this would be your best solution: put all your styles in the same css sheet with a prefixed class for each theme-specific style and then toggleClass() (jQuery) on your html element to and from blackTheme/whiteTheme. This will simplify a lot of your issues and perhaps automatically clear up the scrollbar color issues.

Here's a fiddle to hopefully illustrate the idea. (for simplicity's sake, I only made this work with a 2-way toggle.)

Scrimothy
  • 2,536
  • 14
  • 23
  • hey i tried as you suggested. still scroll bar is not getting changed automatically. I have to either change tab and come back, minimize window or atleat hover mouse over scroll bar. I am thinking there is some other issue . small part of my scroll bar css is something like – javaMan Sep 10 '12 at 18:00
  • .black ::-webkit-scrollbar { background: #323232; width: 11px; height: 11px; } – javaMan Sep 10 '12 at 18:00
  • 1
    Maybe post your html and css, so we can see what you've got so far – Scrimothy Sep 10 '12 at 19:09
  • The `::-webkit-scrollbar` selector is a little tricky – check [this question](http://stackoverflow.com/questions/7743840/apply-webkit-scrollbar-style-to-specified-element/7743982#7743982) or the example in my answer to get an idea of how to use it with this theming approach. – crowjonah Sep 14 '12 at 13:22
2

You need to remove and append the link element.

HTML file

<html>
<head>
<title></title>
<link href="css.css" rel="stylesheet" type="text/css" id="extCSSFile"/>
<script src="jq.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
    $('#bt,#wt').on('click', function(){

        $('#extCSSFile').attr('href',$(this).attr('data-href'));
        var newfile = file = $('#extCSSFile');
        $('#extCSSFile').remove();

        $('head').append($(newfile));
    });
    });
</script>
</head>
<body>
<ul id="nav">
<li id="bt" data-href="css.css">blackTheme</li>
<li id="wt" data-href="css2.css">whiteTheme</li>
</ul>
</body>
</html>

css.css file

ul{height:1000px;}

#bt, #wt{ 
    text-decoration:underline;
    color:blue;
}

::-webkit-scrollbar {
    width: 12px;
}

::-webkit-scrollbar-track {
  background-color:#aaa;
}

::-webkit-scrollbar-thumb {

    background-color:black;
}

css2.css

body{
    background-color:black;
    color:white;
}

ul{height:1000px;}

#bt, #wt{ 
    text-decoration:underline;
    color:blue;
}

::-webkit-scrollbar {
    width: 12px;
}

::-webkit-scrollbar-track {
  background-color:#333;
}

::-webkit-scrollbar-thumb {

    background-color:white;
}
  • 1
    forgot `list-style-type: none;` –  Sep 10 '12 at 21:00
  • I modified my code exactly as you said. But still the problem is not resolved. It is really interesting. I use two monitors. So when i switch from one window to other window it is able to pick up that css change. I am guessing as scroll bar is related to browser, should i do some thing to refresh browser window? – javaMan Sep 11 '12 at 15:00
  • 1
    refresh would reload the whole document. so it's not what you are looking for I guess. Also, in this case I think browser window has to be repainted again. And repaint of the window happens at any event involved with browser, like minimize or maximize. looking into the matter. –  Sep 11 '12 at 15:30
  • is there any way i can kick start window repaint from code without actually doing minimize or maximize – javaMan Sep 11 '12 at 16:30
2

I believe we have a winner here.

This is HTML file code only; css files can what you want them to be.

I wish there was a CSS only method to it. I also didn't find deliberate repaint command for this purpose. One which I did find made use of chrome extensions, weird. But anyway, repainting was easy, all you have to do is shake the painted DOM a bit and you are good to go.

Oh, I am using latest canary build and jQuery; so factor them out in your code. Let me know if there is something amiss.

<link href="" rel="stylesheet" type="text/css" id="extCSSFile"/>

<script src="jquery.js" type="text/javascript"></script>

<script type="text/javascript">
$(function(){

function changeAndPaint(that){

    var filename = $(that).attr('data-href');

$('#extCSSFile').attr('href',filename);
    var newfile = $('#extCSSFile');

    $('#extCSSFile').remove();

    $(that).css('display','none').height(); //<--this is the trick to repaint
    $(that).css('display','inherit');       

    var elem = $('<link href="" rel="stylesheet" type="text/css" id="extCSSFile"/>');
    $(elem).attr('href',filename);  
    $('head').append(e);
}

    $('#bt,#wt').on('click', function(){
            changeAndPaint($(this));
        }); 
    });
  • I am using Latest canary build and jquery 1.7.1 min.js The problem is not resolved even after making this change – javaMan Sep 11 '12 at 17:41
  • hey anubhav, i added the code in my question which i am using based on your code. Let me know if it runs fine on your machine. – javaMan Sep 11 '12 at 19:31
2

None of the other solutions worked for me. I finally got body scrollbars in webkit to redraw by using this:

$('body').hide();
$('body').get(0).offsetHeight;
$('body').show();

...as suggested here: http://www.eccesignum.org/blog/solving-display-refreshredrawrepaint-issues-in-webkit-browsers

Edit: The above javascript will reset the scroll position to the top of the page.

To stay at the same scroll position:

var scrollX = window.pageXOffset;
var scrollY = window.pageYOffset;
$('body').hide();
$('body').get(0).offsetHeight;
$('body').show();
window.scrollTo(scrollX, scrollY);
Jesse Schoff
  • 750
  • 9
  • 24
  • Not the most concise code, but the Edit code sample does in fact force the repaint of the scrollbar, and without blipping the screen. Thanks for your answer. – Chad Jun 11 '19 at 18:15
1

I've elaborated a bit on Scrimothy's solution (and actually wrote my answer before I read his, whoops), and I happen to think it's pretty slick and efficient. I'm not sure why his excellent example wasn't working for you, but perhaps with the webkit scrollbar styles included here, you'll be able to bridge the gap.

Rather than relying on repainting, and multiple css files, use jQuery to toggle a theme-specific class on the body tag, and have all of your css in one file using selectors specific to body.quartz ... and body.carbon....

Check it out in this fiddle: http://jsfiddle.net/crowjonah/Ajkjy/

The script is distilled to this:

$('body').addClass('carbon'); // apply the default theme
$('#carbonTheme').on('click', function(){
    $('body').removeClass('quartz');
    $('body').addClass('carbon');
});
$('#quartzTheme').on('click', function(){
    $('body').removeClass('carbon');
    $('body').addClass('quartz');
});

and your CSS starts to look like this:

body.carbon {
    font-family:Arial,Helvetica,sans-serif;
    font-size:8.5pt;
    width:inherit;
    min-width:100px;
    max-width:250px;
    margin:10px;
    background-color:#191919;
    color:#fff;
}

body.carbon #carbonTheme,body.carbon #quartzTheme {
    text-decoration:underline;
    color:blue;
    cursor:pointer;
}

::-webkit-scrollbar {
    width:12px;
}

body.carbon .constraint::-webkit-scrollbar-track {
    background-color:#aaa;
}

body.carbon .constraint::-webkit-scrollbar-thumb {
    background-color:#000;
}

body.quartz {
    font-family:Arial,Helvetica,sans-serif;
    font-size:8.5pt;
    width:inherit;
    min-width:100px;
    max-width:250px;
    margin:10px;
}

body.quartz #carbonTheme,body.quartz #quartzTheme {
    text-decoration:underline;
    color:blue;
    cursor:pointer;
}

body.quartz .constraint::-webkit-scrollbar-track {
    background-color:#333;
}

body.quartz .constraint::-webkit-scrollbar-thumb {
    background-color:#fff;
}

.constraint {
    height:100px;
    overflow-y:scroll;
}​

Now I admit that there are a lot of potentially valid reasons this might not suit your purposes (especially if you have tons of themes, and they each have a substantial amount of unique styling,) but I think that if you're careful and can define consistent layout things like widths and margins independent of theme, this will save you HTTP requests (as Scrimothy said), allow for faster load times, and prevent you from getting hung up on the hitches of rels, removing and appending link tags, etc.

crowjonah
  • 2,858
  • 1
  • 23
  • 27
  • Valiant effort, and I wanted this to work so bad, but unfortunately it doesn't if the scrollbars are attached to the `body` instead of a `div`: http://jsfiddle.net/Ajkjy/4/ – Jesse Schoff Oct 02 '14 at 19:08