Изменяем СSS в реальном времени

    image

    «О как же достало обновлять страницу браузера после каждой мелкой правки css кода!».

    Решил я это дело автоматизировать, чтобы раз, поменял в своём любимом редакторе код в css, а в браузере тут же изменения отобразились. И так за вечер появилась небольшая библиотечка "cssWatch.js". Не буду долго расписывать, что да как. Только суть.

    И так, что же cssWatch.js делает?

    А делает этот скриптик, то что от него и требуется — обновляет стили css прямо в браузере.

    1. Подключаете cssWatch.js к проекту
    2. Открываете нужную страницу в браузере
    3. Делаете изменения в css файлах, и результат тут же отображается на странице


    Как подключить?


    Подключаем cssWatch.js к странице:

    <!doctype html>
    <html lang="en">
     <head>
      <meta charset="utf-8">
      <title>cssWatch</title>
      <link rel="stylesheet" type="text/css" href="example.css">
      <link rel="stylesheet" type="text/css" href="example2.css">  
    
      <script src="cssWatch.js"></script>    <!-- Здесь -->
    
     </head>
     <body>
         <h2>Попробуйте поменять стили в соответствующих файлах:</h2>
         <div class="b-block">
             example.css
         </div>
         
         <div class="b-block2">
             example2.css
         </div>
     </body>
    </html>
    


    И все, никаких других манипуляций делать не нужно. Теперь стили будут автоматически обновляться.

    Отмечу, что для проверки изменился ли css используются заголовки ответа сервера, т.е. cssWatch.js не будет работать (точнее будет работать не так как ожидается) на файлах, открытых напрямую из файловой системы (например с рабочего стола).

    По умолчанию, скрипт прослушивает все файлы стилей на странице, но можно ненужные отключить. Делается это путём добавления атрибута cssWatch к тегу link:

      <link rel="stylesheet" type="text/css" href="example.css">
      <link rel="stylesheet" cssWatch="no" type="text/css" href="example2.css">  <!--  Этот файл проверяться не будет -->
    


    СssWatch.js можно подключать к любому проекту, с любым уровнем вложенности css файлов.

    Скачать архив с библиотекой и примером.

    Посмотреть в браузере как работает.
    Правда интерактивности нет, т.к. файлы css не меняю, но через консоль браузера можно посмотреть как работает.

    Спасибо за внимание. Буду рад услышать ваше мнение.

    P.S> В IE не тестировал. Пока нет возможности его поставить.

    > Выкладываю исходный код, чтобы не было лишних вопросов:

    Исходный код
     var cssWatch = {  
         /**
          * Интервал проверки изменений css (в миллисекундах)
          */
         interValUpdate: 100,
         
    
    /*------Дальше править не рекомендуется-----------------------------------------------------*/
    
         arrayCssFiles: new Array(),
         arrayLastModified: new Array(),
         arrayCssObj: new Array(),
         counter: 0,
         
         ajax: function (obj) {
             var _this = this;
             var request=null;
             var lastModified = '';
             
             try {
                request = new XMLHttpRequest();
             } catch (e) {
                 try {
                     request=new ActiveXObject("Msxml2.XMLHTTP");
                 } catch (e) {
                     request=new ActiveXObject("Microsoft.XMLHTTP");
                 }
             }
             
             var url = obj.url+'?_=' + Math.random();
             request.onreadystatechange = function (text,text2) {
                 if (request.readyState == 4) {                
                     lastModified = /Last-Modified[]?:([^\n]+)/ig.exec(request.getAllResponseHeaders());
                     lastModified = lastModified[1];
                     
                     if (request.status == 200) {              
                         _this.arrayCssObj[_this.counter].setAttribute('href',_this.arrayCssFiles[_this.counter]+'?_=' + Math.random());
                         if (lastModified) {
                             _this.arrayLastModified[_this.counter] = lastModified.replace(/^\s+/, '').replace(/\s+$/, '');
                         }
                     } 
    
                     setTimeout(function () {
                         if (_this.counter < _this.arrayCssObj.length - 1) {
                             _this.counter++;
                             _this.loadCss();
                         } else {
                             _this.counter = 0;
                             _this.loadCss();
                         }                      
                     },_this.interValUpdate);                 
                 }
             };
    
             request.open("HEAD", url, true);
    
             if (_this.arrayLastModified[_this.counter]) {
                 request.setRequestHeader("If-Modified-Since", _this.arrayLastModified[_this.counter]);
             }
             request.send(null);
             
             return request;         
         },
    
         parse : function () {   
             var _this = this;
             
             var arrayLink = document.getElementsByTagName('link');
             var arrayLinkLength = arrayLink.length;
             
             for (var i = 0; i < arrayLinkLength; i++) {
                 if (arrayLink[i].getAttribute('href').substr(-4) == '.css' && arrayLink[i].getAttribute('cssWatch') != 'no') {
                     _this.arrayCssFiles[_this.arrayCssFiles.length] = arrayLink[i].getAttribute('href');
                     _this.arrayCssObj[_this.arrayCssFiles.length - 1] = arrayLink[i];                 
                 }
             }
    
             if (_this.arrayCssFiles.length > 0) {<b>
                 this.loadCss();
             }</b>
          },
          
         loadCss: function () {
              var _this = this;
                     
              this.ajax({url:_this.arrayCssFiles[_this.counter]});
         },
         
         create: function () {       
             var _this = this;
             
             if (document.readyState == 'complete') {
                 this.init();             
             } else {
                 setTimeout(function () {
                     _this.create();
                 },50);
             }
         }
     };
      
     cssWatch.create();
    




    UPD. На Денвере и подобных пакетах cssWatch.js также работает.
    UPD2. В код закралась опечатка… вместо
        setTimeout(function () {
                     _this.parse();
         },50);
    


    нужно
         setTimeout(function () {
                _this.create();
          },50);
    

    На хабре я скорректировал код. В архиве пока не могу… сегодня поправлю.
    Приношу извинения… подразумевалось так как нужно, просто нельзя скрипты писать «на ночь глядя»
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 62

      +3
      Почему просто по тайм интервалу не добавлять к адресу стилей новый хеш? Тогда и на локальном проекте будет работать.
        +1
        Если просто добавлять хеш, то браузер каждый раз будет грузить стили с сервера заново (по крайне мере хром поступает именно так). А это не есть гуд, ведь файлы стилей могут достаточно много весить — зачем насиловать браузер))
          0
          Можно менять хеш не по таймауту а по размеру файла стилей или по контрольке какой-нить например
          А тут выходит что вы насилуете сервер лишними запросами к нему, пускай и лишь получая заголовки
            0
            размер может быть одинаковым и при разных css стилях)
              0
              Я же написал — размер + дата последнего изменения файла например???
                0
                какая разница… запрос то всеравно делать. Лучше уж тогда HEAD послать
                  0
                  Как раз запрос не надо делать — делаться будет запрос только в случае если поменялся хеш у файла — т.е. если ф файле небыло изменений, тогда файл берется из кеша, если были — тогда урл файла изменился и загрузится новый
                    +1
                    а как вы узнаете дату последней подификации?))))
                      0
                      Я же говорю о стороне сервера. Если php то например filemtime
                        0
                        Мы похоже друг друга не понимаем.
                        Вам в любом случае надо «прозванивать» сервер с вопросом «Изменился ли файл?» и если изменился, то загружать его.
                        Подключать тяжёлый php в данном случае не практично:
                        1) Дополнительная нагрузка (весьма ощутимая)
                        2) Нативные средства (средства веб-сервера) — всегда удобнее и эффективнее
                          0
                          На node.js настроить лонг пулинг, тогда вообще сказка была бы )
                            0
                            к сожалению с node.js не работал… сказать по этому поводу ничего не могу)
                              0
                              А зачем? запустить на локальном сервере и хватит.
                                0
                                Тогда проще поставить плагин для фаерфокса, который сохраняет все изменения в цсс напрямую. Не помню как он называется.
                                +1
                                Да что вы тут развели, какой лонг-пулинг, какие интервалы, F5 (⌘+R) в руки и пошли верстать. С такимы темпами и будете в Дримвивере верстать.
                    0
                    Извините — я выше написал про контрольку, которую действительно тоже геморно каждый раз просчитывать для больших файлов. Тут исправил положение.
                  0
                  Можно это как-нибудь опционально сделать — например, если есть атрибут data-cssWatch-periodical, то включается периодическая загрузка с хэшом. Все-таки для локального проекта тоже хочется использовать.
                    0
                    Локального — это какого?, на Denwer например?
                      0
                      Да нет же:)
                      на файлах, открытых напрямую из файловой системы
                        0
                        хорошо… переработаю в свободное время, чтобы и из фс можно было
                          0
                          Выложите код на гитхаб/битбакет, я могу поучаствовать.
                            0
                            в ближайшее время выложу… наверно завтра
                    0
                    Речь идёт о локальном проекте, а там, зачастую, принципиально именно заново грузить css.
                  +3
                  cssrefresh.frebsite.nl/
                  ну да это вы еще небольшой велосипед построили=)
                    +3
                    1) не знал о его существовании
                    2) «своя рубашка ближе к телу»
                    –1
                    Может лучше заголовком Last-Modified пользоваться?
                      0
                      Они используются)
                      +3
                      Использую github.com/auchenberg/css-reloader
                      Довольно удобно
                        +1
                        Для тех, кто разрабатывает на огнелисе, есть замечательное и легкое приложение CssReset
                          0
                          Можно ссылочку? а то гуглится не связаное с темой.
                          0
                          Для хрома похожее тоже есть.
                          +2
                          Предпочитаю grunt-reload :)
                            0
                            Хорошо бы если бы файл обновлял не только CSS, но и JS и SWF.
                            +5
                            Кроме того есть прекрасная программа LiveReload
                            0
                            Для Chrome давно существует много приложений css reloader
                              0
                              но ведь нужно верстать не только в Хроме… нужно кроссбраузерное решение… скрипт в данном случае необходим… имхо
                                0
                                Потому предупредил что для Chrome. Например, я верстаю всё в Chrome, а потом проверяю в других браузерах, а там не так уж много правок делается, вы ж не версаете весь проект одновременно в всех браузерах.

                                Я не говорю что предложенный скрипт плохой.
                              +1
                              Отличная штука. Спасибо =)
                                +1
                                не за что)
                                0
                                image

                                Конфликтует с расширениями Хрома.

                                То есть, вам нужно добавить проверку, что стили с того же домена нужно только проверять.
                                  0
                                  хорошо… завтра на гитхаб добавлю… и доработаем. Проблема в том, что стили могут быть с разных доменов… следовательно не все так просто)))
                                    0
                                    Как минимум, можете сделать чтобы стили с хромовых расширений игнорировались. Будет универсально.
                                      0
                                      доработаемс))
                                  0
                                  а я просто в файрбаге стиль редактирую, а потом копирую и сохраняю в css-файл
                                    0
                                    firefile — экономит время. изменения сохраняются сразу на сервере и никаких copy-past. работает как расширение для firebug и небольшой северный php. устанавливается за 30 секунд. только, к сожалению -webkit и.т.п может стереть, так что все префиксные правила лучше держать в отдельном файле.
                                    0
                                    а как же live.js?

                                    я использую Drupal, Denwer, Windows.

                                    надо будет проверить, спасибо.
                                    • UFO just landed and posted this here
                                        0
                                        Шикарная штука! Именно такую искал :)
                                        Жаль под «Sublime Text 2» или Zend Studio or Eclipse подобного не находится…
                                        0
                                        Всё-таки подобные вещи нужно делать расширениями к браузеру, а не частью проекта. Нужно следить, чтобы оно не ушло в продакшен, игнорировать в системах контроля версий, следить за подключением в нужных местах и еще много чего. А в браузере — нажал кнопочку и на сайте все стили начали рефрешиться, не зависит от сайта.
                                          0
                                          А просто раз в (несколько) секунд(у) плагином обновлять страницу в браузере не?:) Лично я так и делал.

                                          Идея с js, конечно, интересная, но имеет свои ограничения и немного попахивает извращением:)
                                            +1
                                            Как раз идея с обновлением страницы в браузере попахивает извращением))) —
                                            Представьте себе ситуацию, когда у вас на странице много js и прочего. И страница рендерится до нескольких секунд (например в каких — то сервисах). Тогда обновлением страницы в браузере будет каждый раз довольно медленной операцией))
                                              0
                                              Как уже выше сказали, велик риск оставить это дело в продакшене. Ну и на локалхосте не всегда работать будет)

                                              А так — ну почему бы и нет. Довольно интересное решение, да:)
                                            –1
                                            Чего люди только не придумают, лишь бы не разобраться как работать с какой нибудь IDE
                                              0
                                              поясните плиз))
                                              0
                                              ...
                                                create: function () {       
                                                       var _this = this;
                                                       
                                                       if (document.readyState == 'complete') {
                                                           this.init();             
                                                       } else {
                                                           setTimeout(function () {
                                                               _this.parse();
                                                           },50);
                                                       }
                                                   }
                                              

                                              Оу, а у вас есть метод init? ;)
                                              Вы уверены, что если на момент выполнения вашего кода документ не будет загружен, то это произойдет через 50 ms? По идее нужно дергать не _this.parse() через 50 ms, а _this.create чтобы повторить проверку готовности документа.

                                              СssWatch.js можно подключать к любому проекту, с любым уровнем вложенности css файлов.

                                              Хотите сказать, что если example.css (подключенный как <link rel=«stylesheet» type=«text/css» href=«example.css»>) содержит import 'a.css';, а файл a.css содержит import 'b.css'; и я изменю содержимое b.css, то эти изменения придут в браузер? Судя по вашему коду — это не так. И ни о какой вложенности стилей говорить не приходится. Все подобные решения обновляют только стили подключенные через <link> и не обновляют стили подключенные через import, в чем их главный минус. Так что про вложенность это вы зря.
                                                0
                                                Оу… простите не заметил… опечатка
                                                setTimeout(function () {
                                                        _this.parse();
                                                 },50);
                                                

                                                Вместо _this.parse() конечно же _this.create(); — подразумевалось именно так
                                                Я не имел ввиду import. Я имел ввиду, что независим адрес файла, т.е. «site.ru/e1.css» и «site.ru/bla/bla/2.css» обновятся нормально.
                                                А с import — это да… минус… попробуем доработать)
                                                  0
                                                  Я имел ввиду, что независим адрес файла, т.е. «site.ru/e1.css» и «site.ru/bla/bla/2.css» обновятся нормально.

                                                  Это не вложенность css файлов. Если говорить про файловую систему, то это ее структура, а если говорить про сервер, то это различные идентификаторы ресурсов.
                                                  Под вложенностью же css подразумевается, когда один файл подключает другой.

                                                  А с import — это да… минус… попробуем доработать)

                                                  Это не тривиальная задача и насколько мне известно, пока никто не смог ее решить.
                                                  В целом, подобные вашему решения существуют уже давно, так что, увы, вы не придумали ничего нового. Вот если получится «забороть» import'ы, тогда да — будет что-то новенькое ;)
                                                +1
                                                Мне кажется, что удобней видеть результат после какого-нибудь действия, чтобы видя что было, увидеть что стало.
                                                Для этого удобно подходят расширения типа Reloadt/Reset CSS.

                                                Only users with full accounts can post comments. Log in, please.