Mojo Ribbon — идеальная лента или тригонометрия в LESS

от автора

Доброго времени суток уважаемые хабражители. Недавно в одном проекте мне потребовалось сделать ленточку для блоков. Для примера: очень часто сверху делают ленту с надписью «Fork me on GitHub» или же над каждым элементом в портфолио присутствует лента с датой публикации работы. Лучше покажу пример с официального сайта LESS, так как речь идет о такой маленькой детальке, на которую некоторые могли вообще не обратить внимание.

image

Данный Ribbon — это изображение внутри ссылки с абсолютным позиционированием. Чем меня не устраивает данный вариант? Во-первых: я очень люблю современные стандарты CSS, с помощью которых можно создать приятный дизайн, используя минимум изображений, а в данном случае лентой может быть обычный блок с transform rotate. Во-вторых: с недавнего времени я смотрю на веб сквозь Retina дисплей и неоптимизированные img сразу же бросаются в глаза, но и разработчикам обращать внимание на какую то ленточку, оптимизировать ее отображение с media queries, мне кажеться, даже немного смешно.

Создадим блок длинной 500px, высотой 50px, с абсолютным позиционированием, сверху, слева. Получится то, что мы видим на изображении ниже в левой части. Далее, повернем блок на -45 градусов, чтобы у нас получилось что-то похожее на Ribbon с LESS. Результат показан в правой части изображения. Наш элемент вращается от своего центра, вследствие чего получается отступ слева, а часть будущей ленты выезжает за рабочую область.

image

С помощью инспектора мы можем подобрать нужные нам значения для top и -left. Чем меня не устраивает данный вариант? Во-первых — перфекционизм: я хочу, чтобы максимальное количество указанных пикселей (в данном случае 500) отображалось в рабочей области и не выезжало за нее. Во-вторых — лень: я не хочу при изменении позиции (top, right, bottom, left) и градуса наклона вручную подбирать значения, чтобы спрятать все углы.

Геометрия

Как я и сказал, поворот элемента выполняется от центра. Следовательно, и значения отступов измеряются от края рабочей области до центра. Мысленно представим образующиеся фигуры — треугольники, стороны которых нам необходимо вычислить:
image

Получилось два треугольника ABC и A2B2C2, стороны которых нам необходимо вычислить. Нам известно, что С = 500px (width), С2 = 50px (height), угол наклона -65 (deg), следовательно, угол a в треугольнике ABC равен 65 градусам, а угол b — 25 градусам (180 — 90 — 65). В треугольнике A2B2C2 углы a2 и b2 равны 65 и 25 градусам соответственно.

Тригонометрия

Все просто. Синус угла равен отношению противолежащего катета к гипотинузе. Следовательно:

A = sin(a) * C или A = sin(65) * 500;
B = sin(b) * C или B = sin(25) * 500;

A2 = sin(a2) * C2 или A2 = sin(65) * 50;
B2 = sin(b2) * C2 или B2 = sing(25) * 50;

LESS

.MojoRibbon(@width, @height, @deg, @valign) { 	width: @width; 	height: @height; 	-webkit-box-sizing: border-box;  /* Что бы высота не изменялась при padding */ 	-moz-box-sizing: border-box; 	-ms-box-sizing: border-box; 	box-sizing: border-box; 	.defineDegree(@deg, @valign) when (@deg < 0) and (@valign = top) { 		@degree: -@deg;  /* Угол треугольника неотрицательный, вычисляем правильный  sin */ 		top: @countHeight; 		left: @countWidth;	 		-webkit-transform: rotate(@deg); 		-moz-transform: rotate(@deg); 		-o-transform: rotate(@deg); 		-ms-transform: rotate(@deg); 		transform: rotate(@deg); 	}; 	.defineDegree(@deg, @valign) when (@deg < 0) and (@valign = bottom) { 		@degree: -@deg; /* Угол треугольника неотрицательный, вычисляем правильный  sin */ 		bottom: @countHeight; 		right: @countWidth; /* Если угол поворота отрицательный и в вертикали объект позицианируется по нижнему краю, логически правильно в горизонтали позицианировать его по правому краю */ 		-webkit-transform: rotate(@deg); 		-moz-transform: rotate(@deg); 		-o-transform: rotate(@deg); 		-ms-transform: rotate(@deg); 		transform: rotate(@deg); 	}; 	.defineDegree(@deg, @valign) when (@deg > 0) and (@valign = top) { 		@degree: @deg; 		top: @countHeight; 		right: @countWidth; 		-webkit-transform: rotate(@degree); 		-moz-transform: rotate(@degree); 		-o-transform: rotate(@degree); 		-ms-transform: rotate(@degree); 		transform: rotate(@degree); 	}; 	.defineDegree(@deg, @valign) when (@deg > 0) and (@valign = bottom) { 		@degree: @deg; 		bottom: @countHeight; 		left: @countWidth;  /* Если угол поворота положительный и в вертикали объект позицианируется по верхнему краю, логически правильно в горизонтали позицианировать его по левому краю */ 		-webkit-transform: rotate(@degree); 		-moz-transform: rotate(@degree); 		-o-transform: rotate(@degree); 		-ms-transform: rotate(@degree); 		transform: rotate(@degree); 	}; 	.defineDegree(@deg, @valign) when (@deg = 0) { 		@degree: @deg; 		top: 0; 		left: 0; 	}; 	.defineDegree(@deg, @valign); 	@angleB: 90-@degree; 	@angleB2: @angleB; 	@sideA: round(sin(@degree), 3)*@width; /* Сторона А */ 	@sideB: round(sin(@angleB), 3)*@width; /* Сторона B */ 	@sideB2: round(sin(@angleB2), 3)*@height;  /* Сторона А2 */ 	@sideA2: round(sin(@degree), 3)*@height; /* Сторона B2 */ 	@countHeight: @sideA/2 - @height/2 - @sideB2/2; 	@countWidth: -((@width)-(@sideB))/2 - @sideA2/2;	 } 

Демо результата
GitHub

Большое спасибо всем таким же, как и я CSS занудам за внимание.

ссылка на оригинал статьи http://habrahabr.ru/post/186386/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *