Simulateur Crédit Immobilier
:root {
–primary: #07828e;
–secondary: #6ac0be;
–tertiary: #ff7b07;
–primary-light: #e0f4f5;
–secondary-light: #d5eeee;
–bg: #f7fafa;
–white: #ffffff;
–text: #1a2e2e;
–text-muted: #5a7878;
–border: #c8e0e0;
–radius: 12px;
–radius-sm: 8px;
–success: #1d9e75;
–warning: #ba7517;
–danger: #c0392b;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: ‘Segoe UI’, Arial, sans-serif;
background: var(–bg);
color: var(–text);
min-height: 100vh;
}
.header {
background: var(–primary);
color: #fff;
padding: 28px 32px 24px;
}
.header h1 {
font-size: 22px;
font-weight: 600;
margin-bottom: 4px;
}
.header p { font-size: 14px; opacity: 0.85; }
.nav-tabs {
background: var(–white);
border-bottom: 2px solid var(–primary-light);
display: flex;
gap: 0;
}
.nav-tab {
padding: 14px 24px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
border: none;
background: transparent;
color: var(–text-muted);
border-bottom: 3px solid transparent;
margin-bottom: -2px;
transition: all 0.2s;
}
.nav-tab.active {
color: var(–primary);
border-bottom-color: var(–primary);
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 28px 20px;
}
.panel { display: none; }
.panel.active { display: block; }
.card {
background: var(–white);
border: 1px solid var(–border);
border-radius: var(–radius);
padding: 28px;
margin-bottom: 20px;
}
.card h2 {
font-size: 16px;
font-weight: 600;
color: var(–primary);
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid var(–primary-light);
display: flex;
align-items: center;
gap: 8px;
}
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
}
.form-grid.three { grid-template-columns: 1fr 1fr 1fr; }
@media (max-width: 640px) {
.form-grid, .form-grid.three { grid-template-columns: 1fr; }
}
.form-group {
display: flex;
flex-direction: column;
gap: 6px;
}
label {
font-size: 12px;
font-weight: 700;
color: var(–text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
}
input[type= »number »], input[type= »range »], select {
height: 44px;
border: 1.5px solid var(–border);
border-radius: var(–radius-sm);
padding: 0 14px;
font-size: 15px;
color: var(–text);
background: var(–white);
outline: none;
transition: border-color 0.2s;
width: 100%;
}
input[type= »number »]:focus, select:focus { border-color: var(–primary); }
.input-suffix {
position: relative;
display: flex;
}
.input-suffix input { padding-right: 48px; }
.suffix {
position: absolute;
right: 14px;
top: 50%;
transform: translateY(-50%);
font-size: 13px;
color: var(–text-muted);
pointer-events: none;
}
.slider-row {
display: flex;
align-items: center;
gap: 12px;
}
input[type= »range »] {
flex: 1;
height: 6px;
padding: 0;
accent-color: var(–primary);
cursor: pointer;
}
.slider-val {
min-width: 70px;
text-align: right;
font-size: 15px;
font-weight: 700;
color: var(–primary);
}
.hint { font-size: 12px; color: var(–text-muted); }
.btn {
display: block;
width: 100%;
height: 52px;
background: var(–primary);
color: #fff;
border: none;
border-radius: var(–radius-sm);
font-size: 16px;
font-weight: 600;
cursor: pointer;
margin-top: 24px;
transition: background 0.2s;
}
.btn:hover { background: #056570; }
.results-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
margin-bottom: 20px;
}
@media (max-width: 640px) { .results-grid { grid-template-columns: 1fr; } }
.result-box {
border-radius: var(–radius);
padding: 20px;
text-align: center;
}
.result-box.primary {
background: var(–primary);
color: #fff;
}
.result-box.secondary {
background: var(–primary-light);
border: 1px solid var(–secondary);
}
.result-box .rval {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.5px;
line-height: 1.15;
}
.result-box.secondary .rval { color: var(–primary); }
.result-box .rlbl {
font-size: 13px;
margin-top: 4px;
opacity: 0.8;
}
.result-box.secondary .rlbl { color: var(–text-muted); }
.detail-block {
background: var(–white);
border: 1px solid var(–border);
border-radius: var(–radius);
padding: 20px;
margin-bottom: 20px;
}
.detail-block h3 {
font-size: 14px;
font-weight: 700;
color: var(–primary);
margin-bottom: 14px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.progress-bar {
height: 12px;
border-radius: 6px;
background: var(–primary-light);
overflow: hidden;
margin-bottom: 8px;
}
.progress-fill {
height: 100%;
border-radius: 6px;
background: var(–primary);
transition: width 0.5s;
}
.progress-labels {
display: flex;
justify-content: space-between;
font-size: 12px;
color: var(–text-muted);
margin-bottom: 16px;
}
.taux-indicator {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
border-radius: var(–radius-sm);
font-size: 14px;
font-weight: 600;
margin-bottom: 16px;
}
.taux-ok { background: #e0f4f5; color: var(–primary); }
.taux-warn { background: #faeeda; color: var(–warning); }
.taux-bad { background: #fce8e8; color: var(–danger); }
.dot { width: 10px; height: 10px; border-radius: 50%; }
.dot-ok { background: var(–primary); }
.dot-warn { background: var(–warning); }
.dot-bad { background: var(–danger); }
.amortissement-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
.amortissement-table th {
background: var(–primary-light);
color: var(–primary);
font-weight: 700;
padding: 9px 10px;
text-align: right;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.amortissement-table th:first-child { text-align: left; }
.amortissement-table td {
padding: 8px 10px;
text-align: right;
border-bottom: 1px solid var(–secondary-light);
color: var(–text);
}
.amortissement-table td:first-child { text-align: left; font-weight: 600; }
.amortissement-table tbody tr:last-child td {
border-bottom: none;
font-weight: 700;
background: var(–primary-light);
color: var(–primary);
}
.legend {
display: flex;
gap: 16px;
flex-wrap: wrap;
margin-top: 10px;
}
.legend-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(–text-muted);
}
.legend-dot { width: 10px; height: 10px; border-radius: 2px; }
.hidden { display: none; }
.info-banner {
background: var(–primary-light);
border-left: 4px solid var(–secondary);
border-radius: 0 var(–radius-sm) var(–radius-sm) 0;
padding: 12px 16px;
font-size: 13px;
color: var(–primary);
margin-bottom: 20px;
}
Capacité d’emprunt
Mensualité & coût total
Tableau d’amortissement
Calculez le montant maximum que vous pouvez emprunter en fonction de vos revenus. Le taux d’endettement maximum recommandé est de 35 % (recommandation HCSF 2023).
—
Capacité d’emprunt maximale
—
Budget total d’acquisition (+ apport)
—
Mensualité max (hors assurance)
—
Mensualité max (assurance incluse)
Taux d’endettement
Endettement dans les normes
0 %
35 %
40 %
Calculer ma capacité d’emprunt
—
Mensualité (hors assurance)
—
Mensualité (assurance incluse)
—
Coût total des intérêts
—
Coût total du crédit (tous frais)
Répartition du coût total
Calculer le coût de mon crédit
📊 Paramètres du prêt
Générer le tableau
📅 Tableau d’amortissement annuel
Montants arrondis à l’euro. Résumé par année.
function switchPanel(name, btn) {
document.querySelectorAll(‘.panel’).forEach(p => p.classList.remove(‘active’));
document.querySelectorAll(‘.nav-tab’).forEach(t => t.classList.remove(‘active’));
document.getElementById(‘panel-‘ + name).classList.add(‘active’);
btn.classList.add(‘active’);
}
function fmt(n) {
return Math.round(n).toLocaleString(‘fr-FR’) + ‘ €’;
}
function fmtDec(n, d) {
return n.toLocaleString(‘fr-FR’, { minimumFractionDigits: d, maximumFractionDigits: d });
}
function updateSlider(sliderId, valId, suffix) {
const val = parseFloat(document.getElementById(sliderId).value);
let display = suffix === ‘%’ ? fmtDec(val, 2) + ‘ %’ : val + suffix;
document.getElementById(valId).textContent = display;
}
function mensualiteCredit(capital, tauxAnnuel, dureeAns) {
const tauxM = tauxAnnuel / 100 / 12;
const n = dureeAns * 12;
if (tauxM === 0) return capital / n;
return capital * tauxM / (1 – Math.pow(1 + tauxM, -n));
}
function calcCapacite() {
const rev1 = parseFloat(document.getElementById(‘rev1’).value) || 0;
const rev2 = parseFloat(document.getElementById(‘rev2’).value) || 0;
const autresCredits = parseFloat(document.getElementById(‘autresCredits’).value) || 0;
const apport = parseFloat(document.getElementById(‘apport’).value) || 0;
const taux = parseFloat(document.getElementById(‘tauxC’).value);
const duree = parseInt(document.getElementById(‘dureeC’).value);
const assurance = parseFloat(document.getElementById(‘assuranceC’).value);
const tauxEndet = parseInt(document.getElementById(‘tauxEndet’).value);
updateSlider(‘tauxC’, ‘tauxCVal’, ‘%’);
updateSlider(‘dureeC’, ‘dureeCVal’, ‘ ans’);
updateSlider(‘assuranceC’, ‘assuranceCVal’, ‘%’);
updateSlider(‘tauxEndet’, ‘tauxEndetVal’, ‘%’);
const revTotal = rev1 + rev2;
const mensMax = revTotal * tauxEndet / 100 – autresCredits;
if (mensMax 0 ? (mensAvecAss + autresCredits) / revTotal * 100 : 0;
document.getElementById(‘endetBar’).style.width = Math.min(endetReel / 40 * 100, 100) + ‘%’;
document.getElementById(‘endetLabel’).textContent = fmtDec(endetReel, 1) + ‘ %’;
const ind = document.getElementById(‘tauxEndetIndicator’);
const dot = document.getElementById(‘tauxEndetDot’);
const txt = document.getElementById(‘tauxEndetText’);
if (endetReel <= 33) {
ind.className = 'taux-indicator taux-ok'; dot.className = 'dot dot-ok';
txt.textContent = 'Endettement confortable (' + fmtDec(endetReel, 1) + ' %)';
} else if (endetReel <= 35) {
ind.className = 'taux-indicator taux-warn'; dot.className = 'dot dot-warn';
txt.textContent = 'Endettement dans les limites recommandées (' + fmtDec(endetReel, 1) + ' %)';
} else {
ind.className = 'taux-indicator taux-bad'; dot.className = 'dot dot-bad';
txt.textContent = 'Endettement élevé — risque de refus bancaire (' + fmtDec(endetReel, 1) + ' %)';
}
document.getElementById('resultCapacite').classList.remove('hidden');
}
function calcMensualite() {
const capital = parseFloat(document.getElementById('capital').value) || 0;
const taux = parseFloat(document.getElementById('tauxM').value) || 0;
const duree = parseInt(document.getElementById('dureeM').value) || 1;
const assurance = parseFloat(document.getElementById('assuranceM').value) || 0;
const fraisDossier = parseFloat(document.getElementById('fraisDossier').value) || 0;
const fraisGarantie = parseFloat(document.getElementById('fraisGarantie').value) || 0;
const mens = mensualiteCredit(capital, taux, duree);
const n = duree * 12;
const totalInterets = mens * n – capital;
const totalAssurance = capital * assurance / 100 / 12 * n;
const mensAvecAss = mens + capital * assurance / 100 / 12;
const fraisTotal = fraisDossier + fraisGarantie;
document.getElementById('mensHorsAss').textContent = fmt(mens) + '/mois';
document.getElementById('mensAvecAss').textContent = fmt(mensAvecAss) + '/mois';
document.getElementById('coutInterets').textContent = fmt(totalInterets);
document.getElementById('coutTotal').textContent = fmt(capital + totalInterets + totalAssurance + fraisTotal);
const total = capital + totalInterets + totalAssurance + fraisTotal;
const pC = capital / total * 100;
const pI = totalInterets / total * 100;
const pA = totalAssurance / total * 100;
const pF = fraisTotal / total * 100;
document.getElementById('repartitionBars').innerHTML = `
Capital : ${fmtDec(pC,1)} %
Intérêts : ${fmtDec(pI,1)} %
Assurance : ${fmtDec(pA,1)} %
Frais : ${fmtDec(pF,1)} %
`;
document.getElementById(‘resultMensualite’).classList.remove(‘hidden’);
}
function genererAmortissement() {
const capital = parseFloat(document.getElementById(‘capA’).value) || 0;
const taux = parseFloat(document.getElementById(‘tauxA’).value) || 0;
const duree = parseInt(document.getElementById(‘dureeA’).value) || 1;
const assurance = parseFloat(document.getElementById(‘assuranceA’).value) || 0;
const tauxM = taux / 100 / 12;
const n = duree * 12;
const mens = mensualiteCredit(capital, taux, duree);
let solde = capital;
let totInterets = 0, totAmort = 0, totAss = 0;
let rows = »;
for (let annee = 1; annee <= duree; annee++) {
let iAn = 0, aAn = 0;
for (let m = 0; m < 12; m++) {
const intM = solde * tauxM;
const amM = mens – intM;
iAn += intM; aAn += amM;
solde = Math.max(0, solde – amM);
}
const assAn = capital * assurance / 100;
totInterets += iAn; totAmort += aAn; totAss += assAn;
rows += `
Année ${annee}
${fmt(mens * 12)}
${fmt(aAn)}
${fmt(iAn)}
${fmt(assAn)}
${fmt(Math.max(0, solde))}
`;
}
rows += `
TOTAL
${fmt(mens * n)}
${fmt(totAmort)}
${fmt(totInterets)}
${fmt(totAss)}
0 €
`;
document.getElementById(‘tableAmortissement’).innerHTML = `
Période Annuité totale Amortissement
Intérêts Assurance Capital restant
${rows} `;
document.getElementById(‘resultAmortissement’).classList.remove(‘hidden’);
document.getElementById(‘resultAmortissement’).scrollIntoView({ behavior: ‘smooth’, block: ‘nearest’ });
}
calcCapacite();
calcMensualite();