Яндекс.Метрика

    Песочница

    Создание динамических пользовательских стилей

    Каждый день — новый цветВсем привет!

    Вы, наверное, знаете что такое пользовательские стили.
    Как правило, создатели наших любимых сайтов не балуют нас разнообразием оформления и богатством красок. Поэтому если привычное оформление сайта надоело, на помощь приходят эти самые пользовательские стили. Обратная сторона медали — выбранная тема тоже быстро приедается.

    Сейчас я расскажу, как создать динамический пользовательский стиль, который каждый день красит сайт в случайный цвет.


    Для примера возьму сайт ВКонтакте.

    Динамический стиль будет состоять всего из одной инструкции:
    @import url("http://example.com/dynamic_style.css");
    

    Эта команда импортирует стиль с внешнего сайта. Фишка в том, что этот внешний стиль будет загружаться каждый раз при перезапуске браузера. Как вы уже догадались, этот файл будет динамически генерироваться сервером.

    Для начала напишем заготовку для стиля. Для экономии ресурсов я разбил стиль на 2 части: статическую и динамическую. Статическая часть содержит полупрозрачные изображения в формате base64(чтобы не нагружать сервер лишними запросами). Она также будет подгружаться инструкцией @import. Динамическую часть будет выдавать скрипт на лету.

    Скоро сказка сказывается, да не скоро дело делается. С болванками пришлось порядком повозиться. Я не мастер фотошопа, поэтому не буду описывать процесс создания полупрозрачных изображений, наверняка вы справитесь не хуже меня.

    Вот наконец заготовка динамической части готова. Выглядит она примерно так:
    /* Подключаем статическую часть */
    @import url("http://s.gmjs.ru/css/imports/chameleon/static.css");
    
    /* ... */
    
    #pageHeader .header_back, #pageHeader .header_left{
      background-color:%main% !important;
    }
    
     #vkontakte .fSub, #vkontakte .activePad{
      background-color:%l2%  !important
    }
    
    #vkontakte #profileActions a{
      border-color:%l1% !important;
    }
    
    /* ... */
    


    Теперь осталось написать скрипт. Он должен генерировать случайный цвет (в различных градациях), подставлять цвета в код темы и возвращать результат пользователю.

    В качестве серверной платформы я выбрал Google Apps. При нагрузке до 100 запросов в секунду суточная норма ресурсов расходуется на 10-20%, работает быстро, денег не просит.
    Гораздо эффективнее было бы сделать статический файл со стилем и периодически его обновлять. Но, к сожалению, в Google App Engine нет доступа на запись к файловой системе.

    Код скрипта:
    import random
    import math
    import string
    import colorsys
    
    from google.appengine.ext import webapp
    from google.appengine.ext.webapp.util import run_wsgi_app
    
    
    def readFile():  
      fh = open('color.css')
      return fh.read()
    
    def lighten(arr,val):
      ret=[int(math.floor((1-val)*color+val*255)) for color in arr]
      return ret
    
    def colorstr(arr):
      ret=" rgb("+",".join(["%s" % col for col in arr])+") "
      return ret  
      
    def colorhex(arr):
      colval=arr[0]*256*256+arr[1]*256+arr[2]  
      return "%s" % hex(colval)[2:] 
    
    
    def getRandomColorRGB(min=115,max=240):
      svpart = random.randint(min,max)
      return  [int(round(col*255)) for col in colorsys.hsv_to_rgb(random.randint(0,360)/360.0, svpart/255.0, svpart/255.0)]
      
    def getCSS(maincolor=getRandomColorRGB()):
      color_main=maincolor
      color_dark=[int(math.floor(val*0.95)) for val in color_main]
      color_l1=lighten(color_main,0.85)
      color_l2=lighten(color_main,0.95)
      color_50=lighten(color_main,0.50)
    
      cssres=readFile()
      cssres = string.replace(cssres,"%main%",colorstr(color_main))
      cssres = string.replace(cssres,"%dark%",colorstr(color_dark))
      cssres = string.replace(cssres,"%l1%",colorstr(color_l1))
      cssres = string.replace(cssres,"%l2%",colorstr(color_l2))
      cssres = string.replace(cssres,"%l50%",colorstr(color_50))
      cssres = string.replace(cssres,"%hex%",colorhex(color_main))
      return cssres
    
    class CSSChameleonRandom(webapp.RequestHandler):
      def get(self):
        try:
          cssres=getCSS()
          self.response.headers['Content-Type'] = 'text/css'
          self.response.headers['Cache-control'] = 'no-cache'
          self.response.out.write(cssres)
        except (TypeError, ValueError):    
          self.response.out.write("sorry, error =(")
          raise
    
    application = webapp.WSGIApplication([(r'/vk/chameleon/color/[^\/]+.css', CSSChameleonRandom)
                                         ],
                                         debug=True)
    
    run_wsgi_app(application)
    


    Вот и все, осталось только опубликовать готовый стиль на userstyles.org. Тут нас поджидает засада: userstyles.org не принимает стили с конструкцией @import, если она ссылается на внешний url. Но, как известно, на каждую хитрую гайку…
    @import /*chrome:// */url(http://p.gmjs.ru/vk/chameleon/color/color.css);

    Вот таким несложным способом можно обмануть юзерстайловский фейс-контроль.

    К сожалению, опера не разрешает импорт стилей с внешних адресов. Поэтому для нее придется установить этот стиль в виде скрипта (который можно загрузить там же на userstyles).

    Можно придумать и более интересное применение динамическим стилям. Например, менять стиль в зависимости от времени суток, даты, ip-адреса пользователя и т.д.