Способ иметь отдельную реализацию выглядит следующим образом.
//inner_foo.h
template <typename T>
struct Foo
{
void doSomething(T param);
};
//foo.tpp
#include "inner_foo.h"
template <typename T>
void Foo<T>::doSomething(T param)
{
//implementation
}
//foo.h
#include <foo.tpp>
//main.cpp
#include <foo.h>
inner_foo имеет форвардные объявления. foo.tpp имеет реализацию и включает inner_foo.h; и foo.h будет иметь только одну строку, чтобы включить foo.tpp.
Во время компиляции содержимое foo.h копируется в foo.tpp, а затем весь файл копируется в foo.h после который он компилирует. Таким образом, ограничений нет, и именование согласовано в обмен на один дополнительный файл.
Я делаю это, потому что статические анализаторы для кода разбиваются, когда он не видит передовые объявления класса в * .tpp. Это раздражает при написании кода в любой среде IDE или с помощью YouCompleteMe или других.
Вот такие же идеи, как и в другом ответе, где вы можете сделать это только с одним элементом.
Увеличение ширины / высоты.
const outer = document.querySelector('.outer');
outer.addEventListener('click', () => {
outer.classList.toggle('outer--active');
});
body { overflow: hidden; }
.outer {
width: calc(100px * var(--s,1));
height: calc(100px * var(--s,1));
border-radius: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background:
url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/14.jpg') center ;
transition: all 1.5s;
cursor: pointer;
border: 1px solid black;
}
.outer--active {
--s:4;
}
<div class="outer">
</div>
Учитывая clip-path
, где я добавляю radial-gradient
для создания границы
const outer = document.querySelector('.outer');
outer.addEventListener('click', () => {
outer.classList.toggle('outer--active');
});
body { overflow: hidden; }
.outer {
width: 400px;
height: 400px;
border-radius: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background:
radial-gradient(farthest-side,transparent calc(100% - 3px),#000 100%),
url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/14.jpg');
background-size:40% 40%,auto;
background-position:center;
transition: all 1.5s;
cursor: pointer;
-webkit-clip-path: circle(20% at 50% 50%);
clip-path: circle(20% at 50% 50%);
}
.outer--active {
-webkit-clip-path: circle(50% at 50% 50%);
clip-path: circle(50% at 50% 50%);
background-size:100% 100%,auto;
}
<div class="outer">
</div>
Вы также можете рассмотреть только radial-gradient
, но область щелчка будет больше, и вы не будете иметь прозрачность:
const outer = document.querySelector('.outer');
outer.addEventListener('click', () => {
outer.classList.toggle('outer--active');
});
body { overflow: hidden; }
.outer {
width: 400px;
height: 400px;
border-radius: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background:
radial-gradient(farthest-side,transparent calc(40% - 3px),#000 40%,#fff calc(40% + 1px)),
url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/14.jpg');
background-size:100% 100%,auto;
background-position:center;
transition: all 1.5s;
cursor: pointer;
}
.outer--active {
background-size:240% 240%,auto;
}
<div class="outer">
</div>
То, что вы видите, это не «ошибка браузера», а скорее неправильное понимание того, как работает вычисление двух комбинированных масштабов.
Для простоты, давайте предположим, что функцией перехода является linear
(а не ease
, которая является функцией синхронизации по умолчанию). В этом случае графики обеих шкал будут следующими:
Поскольку мы хотим, чтобы конечная шкала внутреннего элемента оставалась постоянной, то (функция масштабирования) × (функция масштабирования) = 1 для всех временных аргументов. К сожалению, если мы сделаем умножение, в результате мы получим квадратную функцию (в нашем случае это -¾x² + 3x + ¾). Это удар по окончательному масштабированию, который вы можете увидеть в середине перехода. Чтобы избежать этого, вместо перехода к значению scale(n)
нам нужно было бы масштабировать правило m
в scale(1/m)
css. К сожалению, мы не можем этого сделать, даже если мы использовали переменные css, поскольку они (пока) не допускают переходов (см. этот ответ)
Чтобы смягчить это, мы могли бы создать пользовательская функция синхронизации cubic-bezier
, которая была бы обратной к квадратной функции, но я не смог сделать это вручную, и, вероятно, cubic-bezier
не дал бы точную кривую для всех значений времени, особенно если бы мы хотели иметь основание функция синхронизации ничего, кроме linear
.
Подход 1: Вместо масштабирования мы могли бы изменить размеры внешнего div, как показано ниже:
const outer = document.querySelector('.outer');
outer.addEventListener('click', () => {
outer.classList.toggle('outer--active');
});
body { overflow: hidden; }
.outer {
width: 100px;
height: 100px;
overflow: hidden;
border-radius: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform-origin: top left;
transition: all 1s;
cursor: pointer;
border: 1px solid black;
}
.outer--active {
width: 400px;
height: 400px;
}
.inner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
height: 400px;
background: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/14.jpg') center repeat;
transform-origin: top left;
transition: transform 1s;
}
<div class="outer">
<div class="inner"></div>
</div>
Плюсы: сохраняет текущую структуру разметки html
Минусы: анимация прерывистая из-за ошибок браузера, связанных с сглаживанием субпиксельных переходов (например, Отчет об ошибках в Firefox )
Подход 2: Используйте обтравочную маску для эффекта круглого выреза, добавьте div для границы:
const outer = document.querySelector('.outer');
outer.addEventListener('click', () => {
outer.classList.toggle('outer--active');
});
[ 114] <div class="outer">
<div class="inner"></div>
<div class="rim"></div>
</div>
Плюсы: плавно масштабируется
Минусы: необходимо добавить еще один тег HTML для круглой границы / обода. Обод может иногда выглядеть отделенным от внутреннего образа.