Стилизация скролла css и jquery

scrollLeft/scrollTop

Свойства – ширина/высота невидимой, прокрученной в данный момент, части элемента слева и сверху.

Следующая иллюстрация показывает значения и для блока с вертикальной прокруткой.

Другими словами, свойство – это «сколько уже прокручено вверх».

можно изменять

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

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

КликниМеня123456789

Установка значения на или прокрутит элемент в самый верх/низ соответственно.

FAQ

  1. Question: I need padding between border/scrollbar and text, but scrollbar does not
    allow it. What should I do?

    Answer: Wrap the inner content in the div with padding

  2. Question: I need space between content with scrollbar and the rest of the page.
    What should I do?

    Answer: Wrap the scrollable content into container with padding.

  3. Question: If content contains images, content size can be changed after images will
    be loaded. Should I re-initialize scrollbar?

    Answer: No, scrollbar detects content/container size changes automatically and
    recalculates its size or hides/shows scrollbars.

  4. Question: How can I scroll content to a custom position?

    Answer: Use standard jQuery scrollTop/scrollLeft functions on the container.
    For example if you have a container with a class «scrollbar-macosx» use the following code to scroll 50px from top:

    jQuery('.scrollbar-macosx').scrollTop(50);
  5. Question: I want to know when the content is scrolled. Is there any callback for this?

    Answer: Yes, you can use «onScroll» callback (look at AngularJS example),
    or use the standard «scroll» event on the container. For example you have a container with a class
    «scrollbar-macosx», then use the following code to handle the scroll event:

    jQuery('.scrollbar-macosx').not('.scroll-wrapper').on("scroll", function(){
        console.log('content is scrolling');
    });
  6. Question: The scrollbar does not replace the standard scrollbar. What should I do?

    Answer: It’s not a good idea to replace the standard scrollbar for a whole page. But if you
    really need it, wrap all page into container with height/width 100%, overflow: auto and apply
    the scrollbar to this container.

  7. Question: I don’t want to see horizontal scrollbar ever. What should I do?

    Answer: Hide it with CSS like this:

    .scroll-element.scroll-x {
        display: none !important;
    }

    But don’t forget that even if the scrollbar is hidden, the content still may be scrollable horizontally.

  8. Question: Using jQuery’s .width() or .height() on a container
    will return incorrect values. What is going on?

    Answer: Inner scrollable content uses additional height/width & offset of the scrollbar
    to hide it. To get correct height/width values use the visible container:

    jQuery('.scrollbar-macosx').not('.scroll-content').height();
    jQuery('.scrollbar-macosx').not('.scroll-content').width();
  9. Question: How to detect when a DIV is scrolled to the bottom edge?

    Answer: You can make calculations using jQuery’s «scroll» event or you can use
    the «onScroll» callback function that provides information about container’s sizes & offset:

    jQuery('.scrollbar-dynamic').scrollbar({
        "onScroll": function(y, x){
            if(y.scroll == y.maxScroll){
                console.log('Scrolled to bottom');
            }
        }
    });
  10. Question: Can I use jQuery Scrollbar to customize textarea scrollbar?

    Answer: Yes, you can. Textarea scrollbars are supported now.
    Look at Basic Scrollbars Demo page.

  11. Question: Is it possible to set scrollbars max/min size?

    Answer: Use CSS max-height/min-height (max-width/min-width) to set scrollbar size limits.

  12. Question: I have a question / want to report an issue. How can I contact the author?

Стилизация скролла CSS и JQuery

Полосы прокрутки реализованы там, где длина контента превышает ширину окна контейнера. Благодаря этому вы получаете возможность стилизовать iframe, элементы div и поле ввода текста. В iframe и текстовой области окна браузеры автоматически добавляют полосу прокрутки в нижней части, когда содержимое выходит за пределы видимой области. Тем не менее, в контейнерах необходимо предоставлять дополнительную информацию для браузеров. Установка свойству overflow значения scroll говорит браузерам о том, что нужно выводить полосы прокрутки в случае переполнения окна контентом:

//Контейнер, заполненный контентом	
.container {
    width: 100px;
    height: 100px;
    overflow: scroll;
}

Это код scrolling CSS покажет полосу прокрутки такой (справа)

How To Create Smooth Scroll With JS?

Smooth scrolling can also be done through JavaScript and it gives better control over the functionalities. For example, through a smooth scroll with CSS, I can apply the scroll behavior only where the scroll event is built in to be triggered like while clicking the web links. But with JavaScript, I can decide when to scroll and how much to scroll i.e. the offset of the element. In this section, I have modified the same code which I wrote above but here I use a smooth scroll with JS for scrolling to the links. For this, the following built-in JavaScript function is used:

window.scrollTo();

This function can be declared for smooth scroll in JS in two ways:

  1. window.scrollTo(x-coord, y-coord);
  2. window.scrollTo(options)

The x-coord parameter defines the pixel value in the horizontal direction to which the page needs to be scrolled.

The y-coord parameter defines the pixel value in the vertical direction to which the page needs to be scrolled.

The options field depends on the developer. This field is a dictionary parameter that contains a set of options or parameters defining the characteristics of the smooth scroll with JS. To remember this as a stepwise process, we perform the following process to achieve smooth scrolling with JS:

  1. Detect the element you want to connect scrolling to.
  2. Define how much you want to scroll the page.
  3. Trigger the scrolling property within the function.

If you remember these three steps, scrolling smoothly is a very easy part when it comes to the code. But, before taking reference from this code, ensure that you have deleted the following CSS line from the webpage given in the previous section code:

html {

scroll-behavior : smooth;

}

1
2
3
4
5

html{

scroll-behaviorsmooth;

 
}

In the code given in the previous section, add the following code for smooth scroll in JS inside the page at any place:

Now we can relate the code with the steps that I wrote above:

Detecting The Element:

const navlink = document.querySelectorAll(«.navbar a»);

navlink.forEach(elem => elem.addEventListener(«click», smoothscroll));

1
2
3

constnavlink=document.querySelectorAll(«.navbar a»);

navlink.forEach(elem=>elem.addEventListener(«click»,smoothscroll));

In this code for smooth scroll with JS, I am selecting the elements with the class navbar and anchor tags that are within that class. Whenever you click such elements, a function will be triggered with the name smoothscroll.

Define How Much To Scroll:

top: document.querySelector(targetId).offsetTop,

1 topdocument.querySelector(targetId).offsetTop,

In the function smoothscroll, I am defining the pixel value that needs to be scrolled. Since, this cannot be an absolute value, you can make use of the offsetTop function. So, this line returns the offset value for the element being referred to.

Trigger The Scrolling Property Within The function:

With this code, you can trigger the property behavior and set it’s value to “smooth”. This means that you want to scroll smoothly.

This code will generate the same results as from JavaScript.

So with this, are we done with our options of creating a smooth scroll in the page? Well, no! Apart from CSS and JavaScript, we still have another method, smooth scroll with JQuery.

Не стоит брать width/height из CSS

Мы рассмотрели метрики, которые есть у DOM-элементов, и которые можно использовать для получения различных высот, ширин и прочих расстояний.

Но как мы знаем из главы Стили и классы, CSS-высоту и ширину можно извлечь, используя .

Так почему бы не получать, к примеру, ширину элемента при помощи , вот так?

Почему мы должны использовать свойства-метрики вместо этого? На то есть две причины:

  1. Во-первых, CSS-свойства зависят от другого свойства – , которое определяет, «что такое», собственно, эти CSS-ширина и высота. Получается, что изменение , к примеру, для более удобной вёрстки, сломает такой JavaScript.

  2. Во-вторых, в CSS свойства могут быть равны , например, для инлайнового элемента:

    Конечно, с точки зрения CSS – совершенно нормально, но нам-то в JavaScript нужен конкретный размер в , который мы могли бы использовать для вычислений. Получается, что в данном случае ширина из CSS вообще бесполезна.

Есть и ещё одна причина: полоса прокрутки. Бывает, без полосы прокрутки код работает прекрасно, но стоит ей появиться, как начинают проявляться баги. Так происходит потому, что полоса прокрутки «отъедает» место от области внутреннего содержимого в некоторых браузерах. Таким образом, реальная ширина содержимого меньше CSS-ширины. Как раз это и учитывают свойства .

…Но с ситуация иная. Некоторые браузеры (например, Chrome) возвращают реальную внутреннюю ширину с вычетом ширины полосы прокрутки, а некоторые (например, Firefox) – именно CSS-свойство (игнорируя полосу прокрутки). Эти кроссбраузерные отличия – ещё один повод не использовать , а использовать свойства-метрики.

Если ваш браузер показывает полосу прокрутки (например, под Windows почти все браузеры так делают), то вы можете протестировать это сами, нажав на кнопку в ифрейме ниже.

У элемента с текстом в стилях указано CSS-свойство .

На ОС Windows браузеры Firefox, Chrome и Edge резервируют место для полосы прокрутки. Но Firefox отображает , в то время как Chrome и Edge – меньше. Это из-за того, что Firefox возвращает именно CSS-ширину, а остальные браузеры – «реальную» ширину за вычетом прокрутки.

Обратите внимание: описанные различия касаются только чтения свойства из JavaScript, визуальное отображение корректно в обоих случаях

Element

WebKit предоставляет псевлоэлементы ::-webkit-meter-bar, ::-webkit-meter-even-less-good-value, ::-webkit-meter-optimum-value, и ::-webkit-meter-suboptimal-value для кастомизации отображения элемента <meter>.

Для того чтобы псевдоэлементы могли применять стили, вы должны установить свойство -webkit-appearance в значение none на самом элементе <meter>.

Только один из псевдоэлементов ::-webkit-meter-even-less-good-value, ::-webkit-meter-optimum-value, and ::-webkit-meter-suboptimal-value Только один из псевдоэлементов, в зависимости от значения атрибута «value» элемента <meter>.

Взгляните на следующий пример:

<meter low="69" high="80" max="100" optimum="100" value="92">A</meter>
<meter low="69" high="80" max="100" optimum="100" value="72">C</meter>
<meter low="69" high="80" max="100" optimum="100" value="52">E</meter>

meter { -webkit-appearance: none; }
::-webkit-meter-bar {
    height: 50px;
    background: white;
    border: 2px solid black;
}
::-webkit-meter-optimum-value { background: green; }
::-webkit-meter-suboptimum-value { background: orange; }
::-webkit-meter-even-less-good-value { background: blue; }

Вот так это выглядит в Chrome 26 в ОС Х:

Элементы скроллбара

Вы можете управлять отдельными элементами для кастомизации скроллбара:

  • webkit-scrollbar — Все поле скроллбара.
  • webkit-scrollbar-button — Кнопки скрола вверх и вниз (зачастую имеет иконки в виде стрелок).
  • webkit-scrollbar-track — Трек поля по которому передвигается ползунок скролла.
  • webkit-scrollbar-track-piece — Свободное место на треке (которое не занято ползунком).
  • webkit-scrollbar-thumb — Сам ползунок.
  • webkit-scrollbar-corner — Угол на скроллбаре, на котором как правило пересекаются вертикальный и горизонтальный скроллбар.
  • webkit-resizer — Если ваш скроллбар поддерживает изменение размера поля к которому он прикреплен, можете кастомизировать этот элемент.

#

Как получить стиль элемента в jQuery

Первый вариант метода css — это получение окончательного значения CSS-свойства непосредственно применяемого к элементу.

Синтаксис метода :

// Вариант 1 (получение окончательного одного CSS свойства)
.css( propertyName )
// propertyName (тип: Строка) – имя CSS-свойства, значение которого нужно получить
.css( propertyNames )
// propertyName (тип: Массив) – массив, состоящий из одного или нескольких CSS-свойств, значения которых нужно получить

Данный метод, если его применить к набору элементов, возвращает значение CSS свойства только для первого его элемента.

Пример, в котором получим цвет фона непосредственно применённого к элементу :

var bgHeader = $('#header').css('background-color');

В jQuery названия CSS-свойств можно указывать как в CSS, так и как это принято в JavaScript. Т.е. убирать дефисы и заменять буквы, следующие за каждым дефисом на прописные.

// можно и так
var bgHeader = $('#header').css('backgroundColor');

Если необходимо получить значения указанного CSS свойства или набора этих свойств у всех элементов текущего набора, то в этом случае необходимо использовать, например, метод each.

Например, определим значение свойства у всех выбранных элементов и выведем их в консоль:

// переберём все элементы .container
$('.container').each(function(index){
  // значение css-свойства display текущего элемента набора
  var display = $(this).css('display');
  // выведем результат в консоль (индекс элемента в наборе и его значение css-свойства display)
  console.log(index + '. display = '+ display);
});   

Кроме этого, метод позволяет также получить сразу несколько CSS свойств у элемента.

Например, при нажатии на HTML элемент выведим его ширину и высоту:

<div style="width: 100px; height: 100px; background-color: bisque;"></div>
<div style="width: 200px; height: 200px; background-color: lightseagreen;"></div>
...
<script>
  // при нажатии на элемент div
  $('div').click(function () {
    // создадим переменную, которая будет содержать результат
    var output = [];
    // получим значения сразу нескольких CSS свойств
    var cssProperties = $(this).css();
    // переберём полученные свойства
    $.each(cssProperties, function (prop, value) {
      // добавим в массив элемент, содержащий имя свойства и значения
      output.push(prop + ": " + value);
    });
    //выведем массив в качестве содержимого элемента
    $(this).html(output.join('<br>'));
  });
</script>

Customizing a scrollbar design

Example 1

Before diving into customizing the scrollbar, it’s worth talking about the default style in Mac OS. Here is how it looks:

  • The scrollbar track has a border on the left and right sides, with a solid background color.
  • The scrollbar thumb is rounded and with space around it from the left and right sides.

For windows, it’s a bit different.

Here is how we can customize the scrollbar based on the mockup above.

Adding the for both the track and thumb is necessary, as it won’t work on the .

With the new syntax, we can’t adjust the of the scrollbar, and what’s only possible is to change the track and thumb background color.

Note: the next examples only work with the syntax. For a real-life project, you can add both the and the new syntax.

Example 2

For this example, the design is a bit heavier as it contains gradients and shadows. Is that doable? Yes, we can apply inner shadows and gradients to mimic that effect. Let’s see how!

See the Pen
Custom Scrollbar — 2 by Ahmad Shadeed (@shadeed)
on CodePen.

Example 3

We can also add borders to the thumb and track, which can help us with some tricky designs.

Based on the same example, we can reset the top and bottom borders to and get an interesting effect for the thumb. Notice those little elements at the top and bottom of the thumb.

See the Pen
Custom Scrollbar — 3 by Ahmad Shadeed (@shadeed)
on CodePen.

Example 4

In this example, we want the scrollbar thumb to have an offset from all sides. Since it’s not possible to use with the scrollbar properties, we need a hack around that using CSS borders and . I learned about this idea from this great article by Gabriel Romualdo.

By default, when an element has a background and border, the browser will clip the .

Consider the following example:

We have a button with a black border. It doesn’t have padding for the sake of explaining the concept. Suppose that is set to , the border will be included within the size of the button. As a result, the border is appearing above the background.

Now, when we apply , the background will only appear around the content.

I hope the idea is clear. Let’s get back into the scrollbar thumb. To mimic the effect, we need to add the following:

And we’re done.

See the Pen
Custom Scrollbar — 4 by Ahmad Shadeed (@shadeed)
on CodePen.

With that, we have explored how to customize different scrollbar designs. For Firefox, we can use the new syntax but again, it’s limited only to the thickness and solid colors.

Быстрый старт

Подключаем библиотеки и не забываем про CSS:

<link type="text/css" rel="stylesheet" href="css/jquery.jscrollpane.css"/>
<script type="text/javascript" src="js/jquery-1.6.1.min.js" ></script>
<script type="text/javascript" src="js/jquery.mousewheel.js"></script>
<script type="text/javascript" src="js/jquery.jscrollpane.js"></script>

В HTML каким-либо способом выделяем контейнер для скролла (например, присваиваем класс):

<div class="scroll-pane">
		Хочу себе необычный скролл!
</div>

В CSS задаем оформление контейнера:

.scroll-pane {
	width: 400px; /* Ширина видимой области*/
	height: 275px; /* Высота видимой области*/
	overflow: auto; /* Если отключены скрипты это правило позволит отобразить обычный скролл */
}

Настраиваем стили из jquery.jscrollpane.css (подробнее об этом немного ниже).

Последний шаг — инициализируем скролл скриптом:

<script type="text/javascript">
	jQuery(function()
	{
		jQuery('.scroll-pane').jScrollPane();
	});
</script>

Примеры

Инициализация с использованием стрелок для прокрутки:

jQuery('.scroll-pane').jScrollPane({showArrows: true});

Задаем минимальную и максимальную длину ползунка прокрутки:

jQuery('.scroll-pane').jScrollPane(
	{
		verticalDragMinHeight: 20,
		verticalDragMaxHeight: 20,
		horizontalDragMinWidth: 20,
		horizontalDragMaxWidth: 20
	}
)

Пример вызова API для программной перемотки скроллбара:

var pane = jQuery('.scroll-pane');
pane.jScrollPane(
	{
		showArrows: true
	}
);
var api = pane.data('jsp');
jQuery('#but-scroll').bind(
	'click',
	function()
	{
		api.scrollTo(100, 100);
		return false;
	}
);

Минусы:

  • немного великоват (в несжатом виде 44Kb, в сжатом 14.6Kb);
  • прокрутка колесиком мыши «не дружит» с горизонтальным скроллом.

Невооруженным глазом видно, что плагин стал гораздо мощнее, по сравнению с первой версией, хотя, конечно за это приходится расплачиваться — размер скрипта вырос вдвое.

Исследования

В отчете Уильяма Бакстона и Брэда Майерса за 1986 год были протестированы различные способы взаимодействия двумя руками, включая прокрутку, щелчок и изменение размера. В их исследовании щелчок и изменение размера выполнялись параллельно. В первом эксперименте участникам предлагалось выполнить задачу выбора / позиционирования, а во втором эксперименте участникам предлагалось выполнить сложную задачу навигации / выбора. Исследование показало, что пользователи могут выполнять эти задачи быстрее и параллельно, когда они используют обе руки, но не обязательно, когда они используют обе руки одновременно. Они также обнаружили, что чем более взаимосвязанными были задачи, которые пользователь выполнял каждой рукой, тем быстрее они выполняли задачи, которые их просили выполнить.

Необходимое

Вот псевдоэлементы, отвечающие за разные части полос прокрутки.

CSS

Различные состояния

Это псевдоселекторы, они позволяют точнее выбирать разные части полосы прокрутки, когда они находятся в различных состояниях.

CSS

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

:horizontal — применяется к любому скроллбару, который имеет горизонтальную ориентацию.

:vertical — применяется к любому скроллбару, который имеет вертикальную ориентацию.

:decrement — применяется к кнопкам и к видимой части трека, сообщает, что нет кнопок или видимая часть трека уменьшена в процессе использования (вверх для вертикального скроллбара и влево для горизонтального).

:increment — применяется к кнопкам и к видимой части трека, сообщает, что нет кнопок или видимая часть трека увеличена в процессе использования (вниз для вертикального скроллбара и вправо для горизонтального).

:start — применяется к кнопкам и к видимой части трека, сообщает, что объект находится перед ползунком.

:end — применяется к кнопкам и к видимой части трека, сообщает, что объект находится после ползунка.

:double-button — применяется к кнопкам и к видимой части трека, используется для определения того, что кнопка является частью пары кнопок, которые находятся вместе в конце скроллбара. Для видимой части трека сообщает, что она примыкает к паре кнопок.

:single-button — применяется к кнопкам и к видимой части трека, используется для определения того, что кнопка в конце скроллбара единственная. Для видимой части трека сообщает, что он примыкает к этой единственной кнопке.

:no-button — применяется к видимой части трека, сообщает, что видимая часть трека приближается к краю скроллбара, другими словами, нет кнопки в конце трека.

:corner-present — применяется ко всем элементам скроллбара и сообщает, что имеется уголок.

:window-inactive — применяется ко всем элементам скроллбара и сообщает, что окно со скроллбаром в данный момент активно. В последних версиях этот псевдокласс хорошо сочетается с ::selection. Мы планируем расширить его работу для любого контента и предложить в качестве нового стандартного псевдокласса.

Select

На HTML страничку селекты выводятся так:

<select>
	<option value="">Укажите возраст</option>
	<option value="0 - 12 месяцев">0 - 12 месяцев</option>
	<option value="1 - 3 года">1 - 3 года</option>
	<option value="3 - 5 лет">3 - 5 лет</option>
	<option value="Больше 5 лет">Больше 5 лет</option>
</select>

Реально кучу плагинов jQuery для их стилизации, но мой метод я считаю самый правильный, суть его такая же как и в случае с radio кнопками, только здесь вместо дивов будет использоваться список, который выпадает по клику на ссылку, а потом при клике на ссылку из выпадающего списка ее текстовое значение будет заносится в скрытый инпут и в первую ссылку по которой кликнули. Все очень просто)))

HTML рзаметка выглядит следующим образом:

<div class="select">
	<a href="javascript:void(0);" class="slct">Выберите Ваше лучшее качество:</a>
	<ul class="drop">
		<li><a href="">Красивый(ая)</a></li>
		<li><a href="">Умный(ая)</a></li>
		<li><a href="">Коммуникабульный(ая)</a></li>
		<li><a href="">Скромный(ая)</a></li>
	</ul>
	<input type="hidden" id="select" />
</div>

Теперь добавим стилей для всего этого дела

/*	=	Select */
.slct {
	display: block;
	border-radius: 5px;
	border: 1px solid #cecece;
	background-color: #F6F6f6;
	width: 285px;
	padding: 4px 15px 4px 10px;
	color: #444;
	background-position: 290px -145px;

	/*
		Супер финт обрезаем текст
		чтобы не вылезал за рамку
	*/
	overflow: hidden;
	white-space:nowrap;
	text-overflow: ellipsis;
	-o-text-overflow: ellipsis;	

}
.slct.active {
	border-radius: 5px 5px 0 0;
	border-bottom: none;
}
.drop {
	margin: 0;
	padding: 0;
	width: 310px;
	border: 1px solid #cecece;
	border-top: none;
	display: none;
	position: absolute;
	background: #fff;
}
.drop li {
	list-style: none;
	border-top: 1px dotted #e8e8e8;
	cursor: pointer;
	display: block;
	color: #444;
	padding: 4px 15px 4px 25px;
	background-position: 10px -119px;
}
.drop li:hover {
	background-color: #e8e8e8;
	color: #222;
}

ну и без jQuery опять никуда:

// Select
$('.slct').click(function(){
	/* Заносим выпадающий список в переменную */
	var dropBlock = $(this).parent().find('.drop');

	/* Делаем проверку: Если выпадающий блок скрыт то делаем его видимым*/
	if( dropBlock.is(':hidden') ) {
		dropBlock.slideDown();

		/* Выделяем ссылку открывающую select */
		$(this).addClass('active');

		/* Работаем с событием клика по элементам выпадающего списка */
		$('.drop').find('li').click(function(){

			/* Заносим в переменную HTML код элемента
			списка по которому кликнули */
			var selectResult = $(this).html();

			/* Находим наш скрытый инпут и передаем в него
			значение из переменной selectResult */
			$(this).parent().parent().find('input').val(selectResult);

			/* Передаем значение переменной selectResult в ссылку которая
			открывает наш выпадающий список и удаляем активность */
			$(this).parent().parent().find('.slct').removeClass('active').html(selectResult);

			/* Скрываем выпадающий блок */
			dropBlock.slideUp();
		});

	/* Продолжаем проверку: Если выпадающий блок не скрыт то скрываем его */
	} else {
		$(this).removeClass('active');
		dropBlock.slideUp();
	}

	/* Предотвращаем обычное поведение ссылки при клике */
	return false;
});

Дальше займемся кнопками загрузить изображение и кнопкой отправкой формы.

Hidden

Это значение противоположность . Оно скрывает любой контент, выходящий за рамки контейнера. Повторим первый пример, но с примененным к контейнеру свойством:

See the Pen
overflow hidden by Андрей (@adlibi)
on CodePen.

Текст, который выходит за пределы , перестал быть видимым.

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

Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Люкс-хост
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: